diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index e60595e8b9..cf1cd5b9ff 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -54,4 +54,13 @@ steps: # Code quality - label: "Code quality" - command: "./tools/check/check_code_quality.sh" + command: + - "./tools/check/check_code_quality.sh" + + - label: "ktlint" + command: + - "curl -sSLO https://github.com/pinterest/ktlint/releases/download/0.34.2/ktlint && chmod a+x ktlint" + - "./ktlint --android --experimental -v" + plugins: + - docker#v3.1.0: + image: "openjdk" diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000000..19a95806d3 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,32 @@ +# For ktlint configuration. Ref: https://ktlint.github.io/ + +[*.{kt,kts}] +# possible values: number (e.g. 2), "unset" (makes ktlint ignore indentation completely) +indent_size=unset +# true (recommended) / false +insert_final_newline=true +# possible values: number (e.g. 120) (package name, imports & comments are ignored), "off" +# it's automatically set to 100 on `ktlint --android ...` (per Android Kotlin Style Guide) +max_line_length=off + +# Comma-separated list of rules to disable (Since 0.34.0) +# Note that rules in any ruleset other than the standard ruleset will need to be prefixed +# by the ruleset identifier. +disabled_rules=no-wildcard-imports,no-multi-spaces,colon-spacing,chain-wrapping,import-ordering,experimental:annotation + +# The following (so far identified) rules are kept: +# no-blank-line-before-rbrace +# final-newline +# no-consecutive-blank-lines +# comment-spacing +# filename +# comma-spacing +# paren-spacing +# op-spacing +# string-template +# no-unused-imports +# curly-spacing +# no-semi +# no-empty-class-body +# experimental:multiline-if-else +# experimental:no-empty-first-line-in-method-block diff --git a/.gitignore b/.gitignore index 0722110715..76cd170215 100644 --- a/.gitignore +++ b/.gitignore @@ -1,14 +1,18 @@ *.iml .gradle /local.properties -.idea/* -/.idea/* -/.idea/libraries -/.idea/modules.xml -/.idea/workspace.xml +# idea files: exclude everything except dictionnaries +.idea/caches +.idea/codeStyles +.idea/libraries +.idea/*.xml .DS_Store /build /captures .externalNativeBuild /tmp + +ktlint +.idea/copyright/New_vector.xml +.idea/copyright/profiles_settings.xml diff --git a/.idea/dictionaries/bmarty.xml b/.idea/dictionaries/bmarty.xml new file mode 100644 index 0000000000..01981ada12 --- /dev/null +++ b/.idea/dictionaries/bmarty.xml @@ -0,0 +1,19 @@ + + + + backstack + bytearray + ciphertext + decryptor + emoji + emojis + hmac + ktlint + linkified + linkify + megolm + pbkdf + pkcs + + + \ No newline at end of file diff --git a/CHANGES.md b/CHANGES.md index 22701ff529..48d0be34cd 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,29 @@ +Changes in RiotX 0.7.0 (2019-10-24) +=================================================== + +Features: + - Share elements from other app to RiotX (#58) + - Read marker (#84) + - Add ability to report content (#515) + +Improvements: + - Persist active tab between sessions (#503) + - Do not upload file too big for the homeserver (#587) + - Attachments: start using system pickers (#52) + - Mark all messages as read (#396) + +Other changes: + - Accessibility improvements to read receipts in the room timeline and reactions emoji chooser + +Bugfix: + - Fix issue on upload error in loop (#587) + - Fix opening a permalink: the targeted event is displayed twice (#556) + - Fix opening a permalink paginates all the history up to the last event (#282) + - after login, the icon in the top left is a green 'A' for (all communities) rather than my avatar (#267) + - Picture uploads are unreliable, pictures are shown in wrong aspect ratio on desktop client (#517) + - Invitation notifications are not dismissed automatically if room is joined from another client (#347) + - Opening links from RiotX reuses browser tab (#599) + Changes in RiotX 0.6.1 (2019-09-24) =================================================== @@ -141,21 +167,21 @@ Mode details here: https://medium.com/@RiotChat/introducing-the-riotx-beta-for-a Changes in RiotX 0.0.0 (2019-XX-XX) =================================================== -Features: +Features ✨: - -Improvements: +Improvements 🙌: - Other changes: - -Bugfix: +Bugfix 🐛: - -Translations: +Translations 🗣: - -Build: +Build 🧱: - diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 449f6421cf..d64dd7110e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -40,19 +40,45 @@ Please add a line to the top of the file `CHANGES.md` describing your change. Make sure the following commands execute without any error: -> ./tools/check/check_code_quality.sh +#### Internal tool -> ./gradlew lintGplayRelease +
+./tools/check/check_code_quality.sh
+
+ +#### ktlint + +
+curl -sSLO https://github.com/pinterest/ktlint/releases/download/0.34.2/ktlint && chmod a+x ktlint
+./ktlint --android --experimental -v
+
+ +Note that you can run + +
+./ktlint --android --experimental -v -F
+
+ +For ktlint to fix some detected errors for you (you still have to check and commit the fix of course) + +#### lint + +
+./gradlew lintGplayRelease
+./gradlew lintFdroidRelease
+
### Unit tests Make sure the following commands execute without any error: -> ./gradlew testGplayReleaseUnitTest +
+./gradlew testGplayReleaseUnitTest
+
### Tests -RiotX is currently supported on Android Jelly Bean (API 16+): please test your change on an Android device (or Android emulator) running with API 16. Many issues can happen (including crashes) on older devices. +RiotX is currently supported on Android KitKat (API 19+): please test your change on an Android device (or Android emulator) running with API 19. Many issues can happen (including crashes) on older devices. Also, if possible, please test your change on a real device. Testing on Android emulator may not be sufficient. ### Internationalisation diff --git a/build.gradle b/build.gradle index b52707d527..714152370e 100644 --- a/build.gradle +++ b/build.gradle @@ -1,9 +1,7 @@ -import javax.tools.JavaCompiler - // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - ext.kotlin_version = '1.3.21' + ext.kotlin_version = '1.3.50' repositories { google() jcenter() @@ -12,11 +10,11 @@ buildscript { } } dependencies { - classpath 'com.android.tools.build:gradle:3.4.1' - classpath 'com.google.gms:google-services:4.2.0' - classpath "com.airbnb.okreplay:gradle-plugin:1.4.0" + classpath 'com.android.tools.build:gradle:3.5.1' + classpath 'com.google.gms:google-services:4.3.2' + classpath "com.airbnb.okreplay:gradle-plugin:1.5.0" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - classpath 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.6.2' + classpath 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.7.1' classpath 'com.google.android.gms:oss-licenses-plugin:0.9.5' // NOTE: Do not place your application dependencies here; they belong @@ -61,6 +59,11 @@ allprojects { ] } + tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all { + // Warnings are potential errors, so stop ignoring them + kotlinOptions.allWarningsAsErrors = true + } + afterEvaluate { extensions.findByName("kapt")?.arguments { arg("dagger.gradle.incremental", "enabled") diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 240d7e10ef..51b92600a0 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Tue Mar 19 09:53:05 CET 2019 +#Fri Sep 27 10:10:35 CEST 2019 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.2.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip diff --git a/matrix-sdk-android-rx/build.gradle b/matrix-sdk-android-rx/build.gradle index 6e24d1d582..31f928c241 100644 --- a/matrix-sdk-android-rx/build.gradle +++ b/matrix-sdk-android-rx/build.gradle @@ -5,8 +5,6 @@ apply plugin: 'kotlin-kapt' android { compileSdkVersion 28 - - defaultConfig { minSdkVersion 16 targetSdkVersion 28 @@ -14,7 +12,6 @@ android { versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - } buildTypes { @@ -29,12 +26,14 @@ android { targetCompatibility JavaVersion.VERSION_1_8 } - + kotlinOptions { + jvmTarget = "1.8" + } } dependencies { implementation project(":matrix-sdk-android") - implementation 'androidx.appcompat:appcompat:1.1.0-beta01' + implementation 'androidx.appcompat:appcompat:1.1.0' implementation 'io.reactivex.rxjava2:rxkotlin:2.3.0' implementation 'io.reactivex.rxjava2:rxandroid:2.1.1' // Paging diff --git a/matrix-sdk-android-rx/src/main/java/im/vector/matrix/rx/LiveDataObservable.kt b/matrix-sdk-android-rx/src/main/java/im/vector/matrix/rx/LiveDataObservable.kt index a1943bbe1c..7958d3efa1 100644 --- a/matrix-sdk-android-rx/src/main/java/im/vector/matrix/rx/LiveDataObservable.kt +++ b/matrix-sdk-android-rx/src/main/java/im/vector/matrix/rx/LiveDataObservable.kt @@ -20,7 +20,6 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.Observer import io.reactivex.Observable import io.reactivex.android.MainThreadDisposable -import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.schedulers.Schedulers private class LiveDataObservable( @@ -60,4 +59,4 @@ private class LiveDataObservable( fun LiveData.asObservable(): Observable { return LiveDataObservable(this).observeOn(Schedulers.computation()) -} \ No newline at end of file +} diff --git a/matrix-sdk-android-rx/src/main/java/im/vector/matrix/rx/MatrixCallbackCompletable.kt b/matrix-sdk-android-rx/src/main/java/im/vector/matrix/rx/MatrixCallbackCompletable.kt index 58c015dfdd..cf0e955b00 100644 --- a/matrix-sdk-android-rx/src/main/java/im/vector/matrix/rx/MatrixCallbackCompletable.kt +++ b/matrix-sdk-android-rx/src/main/java/im/vector/matrix/rx/MatrixCallbackCompletable.kt @@ -19,7 +19,6 @@ package im.vector.matrix.rx import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.util.Cancelable import io.reactivex.CompletableEmitter -import io.reactivex.SingleEmitter internal class MatrixCallbackCompletable(private val completableEmitter: CompletableEmitter) : MatrixCallback { @@ -36,4 +35,4 @@ fun Cancelable.toCompletable(completableEmitter: CompletableEmitter) { completableEmitter.setCancellable { this.cancel() } -} \ No newline at end of file +} diff --git a/matrix-sdk-android-rx/src/main/java/im/vector/matrix/rx/MatrixCallbackSingle.kt b/matrix-sdk-android-rx/src/main/java/im/vector/matrix/rx/MatrixCallbackSingle.kt index 8d554df270..d638354dfd 100644 --- a/matrix-sdk-android-rx/src/main/java/im/vector/matrix/rx/MatrixCallbackSingle.kt +++ b/matrix-sdk-android-rx/src/main/java/im/vector/matrix/rx/MatrixCallbackSingle.kt @@ -35,4 +35,4 @@ fun Cancelable.toSingle(singleEmitter: SingleEmitter) { singleEmitter.setCancellable { this.cancel() } -} \ No newline at end of file +} diff --git a/vector/src/main/java/im/vector/riotx/core/dialogs/DialogSendItemAdapter.kt b/matrix-sdk-android-rx/src/main/java/im/vector/matrix/rx/OptionalRx.kt similarity index 72% rename from vector/src/main/java/im/vector/riotx/core/dialogs/DialogSendItemAdapter.kt rename to matrix-sdk-android-rx/src/main/java/im/vector/matrix/rx/OptionalRx.kt index 8689168e77..d608837d4a 100644 --- a/vector/src/main/java/im/vector/riotx/core/dialogs/DialogSendItemAdapter.kt +++ b/matrix-sdk-android-rx/src/main/java/im/vector/matrix/rx/OptionalRx.kt @@ -14,13 +14,11 @@ * limitations under the License. */ -package im.vector.riotx.core.dialogs +package im.vector.matrix.rx -import android.content.Context +import im.vector.matrix.android.api.util.Optional +import io.reactivex.Observable -internal class DialogSendItemAdapter(context: Context, items: MutableList) : DialogAdapter(context) { - - init { - addAll(items) - } +fun Observable>.unwrap(): Observable { + return filter { it.hasValue() }.map { it.get() } } diff --git a/matrix-sdk-android-rx/src/main/java/im/vector/matrix/rx/RxRoom.kt b/matrix-sdk-android-rx/src/main/java/im/vector/matrix/rx/RxRoom.kt index 28a3d40070..e058b2716c 100644 --- a/matrix-sdk-android-rx/src/main/java/im/vector/matrix/rx/RxRoom.kt +++ b/matrix-sdk-android-rx/src/main/java/im/vector/matrix/rx/RxRoom.kt @@ -22,25 +22,34 @@ import im.vector.matrix.android.api.session.room.model.ReadReceipt import im.vector.matrix.android.api.session.room.model.RoomSummary import im.vector.matrix.android.api.session.room.send.UserDraft import im.vector.matrix.android.api.session.room.timeline.TimelineEvent +import im.vector.matrix.android.api.util.Optional import io.reactivex.Observable import io.reactivex.Single class RxRoom(private val room: Room) { - fun liveRoomSummary(): Observable { - return room.liveRoomSummary().asObservable() + fun liveRoomSummary(): Observable> { + return room.getRoomSummaryLive().asObservable() } fun liveRoomMemberIds(): Observable> { return room.getRoomMemberIdsLive().asObservable() } - fun liveAnnotationSummary(eventId: String): Observable { + fun liveAnnotationSummary(eventId: String): Observable> { return room.getEventSummaryLive(eventId).asObservable() } - fun liveTimelineEvent(eventId: String): Observable { - return room.liveTimeLineEvent(eventId).asObservable() + fun liveTimelineEvent(eventId: String): Observable> { + return room.getTimeLineEventLive(eventId).asObservable() + } + + fun liveReadMarker(): Observable> { + return room.getReadMarkerLive().asObservable() + } + + fun liveReadReceipt(): Observable> { + return room.getMyReadReceiptLive().asObservable() } fun loadRoomMembersIfNeeded(): Single = Single.create { @@ -58,9 +67,8 @@ class RxRoom(private val room: Room) { fun liveDrafts(): Observable> { return room.getDraftsLive().asObservable() } - } fun Room.rx(): RxRoom { return RxRoom(this) -} \ No newline at end of file +} diff --git a/matrix-sdk-android-rx/src/main/java/im/vector/matrix/rx/RxSession.kt b/matrix-sdk-android-rx/src/main/java/im/vector/matrix/rx/RxSession.kt index f3fb06a45a..f19777b6f5 100644 --- a/matrix-sdk-android-rx/src/main/java/im/vector/matrix/rx/RxSession.kt +++ b/matrix-sdk-android-rx/src/main/java/im/vector/matrix/rx/RxSession.kt @@ -24,6 +24,7 @@ import im.vector.matrix.android.api.session.room.model.RoomSummary import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams import im.vector.matrix.android.api.session.sync.SyncState import im.vector.matrix.android.api.session.user.model.User +import im.vector.matrix.android.api.util.Optional import io.reactivex.Observable import io.reactivex.Single @@ -45,6 +46,10 @@ class RxSession(private val session: Session) { return session.livePushers().asObservable() } + fun liveUser(userId: String): Observable> { + return session.liveUser(userId).asObservable().distinctUntilChanged() + } + fun liveUsers(): Observable> { return session.liveUsers().asObservable() } @@ -66,9 +71,8 @@ class RxSession(private val session: Session) { fun joinRoom(roomId: String, viaServers: List = emptyList()): Single = Single.create { session.joinRoom(roomId, viaServers, MatrixCallbackSingle(it)).toSingle(it) } - } fun Session.rx(): RxSession { return RxSession(this) -} \ No newline at end of file +} diff --git a/matrix-sdk-android/build.gradle b/matrix-sdk-android/build.gradle index 8002625e12..3e6d3ea88b 100644 --- a/matrix-sdk-android/build.gradle +++ b/matrix-sdk-android/build.gradle @@ -67,6 +67,10 @@ android { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } + + kotlinOptions { + jvmTarget = "1.8" + } } static def gitRevision() { @@ -86,41 +90,43 @@ static def gitRevisionDate() { dependencies { - def arrow_version = "0.8.0" - def support_version = '1.1.0-beta01' + def arrow_version = "0.8.2" def moshi_version = '1.8.0' - def lifecycle_version = '2.0.0' - def coroutines_version = "1.0.1" - def markwon_version = '3.0.0' - def daggerVersion = '2.23.1' + def lifecycle_version = '2.1.0' + def coroutines_version = "1.3.2" + def markwon_version = '3.1.0' + def daggerVersion = '2.24' implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version" - implementation "androidx.appcompat:appcompat:1.1.0-rc01" - implementation "androidx.recyclerview:recyclerview:1.1.0-beta01" + implementation "androidx.appcompat:appcompat:1.1.0" + implementation "androidx.recyclerview:recyclerview:1.1.0-beta05" implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version" kapt "androidx.lifecycle:lifecycle-compiler:$lifecycle_version" // Network - implementation 'com.squareup.retrofit2:retrofit:2.6.0' - implementation 'com.squareup.retrofit2:converter-moshi:2.4.0' - implementation 'com.squareup.okhttp3:okhttp:3.14.1' - implementation 'com.squareup.okhttp3:logging-interceptor:3.10.0' + implementation 'com.squareup.retrofit2:retrofit:2.6.2' + implementation 'com.squareup.retrofit2:converter-moshi:2.6.2' + implementation 'com.squareup.okhttp3:okhttp:4.2.2' + implementation 'com.squareup.okhttp3:logging-interceptor:4.2.2' implementation 'com.novoda:merlin:1.2.0' implementation "com.squareup.moshi:moshi-adapters:$moshi_version" kapt "com.squareup.moshi:moshi-kotlin-codegen:$moshi_version" implementation "ru.noties.markwon:core:$markwon_version" + // Image + implementation 'androidx.exifinterface:exifinterface:1.0.0' + // Database implementation 'com.github.Zhuinden:realm-monarchy:0.5.1' kapt 'dk.ilios:realmfieldnameshelper:1.1.1' // Work - implementation "androidx.work:work-runtime-ktx:2.1.0-rc01" + implementation "androidx.work:work-runtime-ktx:2.3.0-alpha01" // FP implementation "io.arrow-kt:arrow-core:$arrow_version" @@ -132,24 +138,24 @@ dependencies { // DI implementation "com.google.dagger:dagger:$daggerVersion" kapt "com.google.dagger:dagger-compiler:$daggerVersion" - compileOnly 'com.squareup.inject:assisted-inject-annotations-dagger2:0.4.0' - kapt 'com.squareup.inject:assisted-inject-processor-dagger2:0.4.0' + compileOnly 'com.squareup.inject:assisted-inject-annotations-dagger2:0.5.0' + kapt 'com.squareup.inject:assisted-inject-processor-dagger2:0.5.0' // Logging implementation 'com.jakewharton.timber:timber:4.7.1' - implementation 'com.facebook.stetho:stetho-okhttp3:1.5.0' + implementation 'com.facebook.stetho:stetho-okhttp3:1.5.1' // Bus implementation 'org.greenrobot:eventbus:3.1.1' - debugImplementation 'com.airbnb.okreplay:okreplay:1.4.0' - releaseImplementation 'com.airbnb.okreplay:noop:1.4.0' - androidTestImplementation 'com.airbnb.okreplay:espresso:1.4.0' + debugImplementation 'com.airbnb.okreplay:okreplay:1.5.0' + releaseImplementation 'com.airbnb.okreplay:noop:1.5.0' + androidTestImplementation 'com.airbnb.okreplay:espresso:1.5.0' testImplementation 'junit:junit:4.12' - testImplementation 'org.robolectric:robolectric:4.0.2' + testImplementation 'org.robolectric:robolectric:4.3' //testImplementation 'org.robolectric:shadows-support-v4:3.0' - testImplementation "io.mockk:mockk:1.8.13.kotlin13" + testImplementation 'io.mockk:mockk:1.9.3.kotlin12' testImplementation 'org.amshove.kluent:kluent-android:1.44' testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version" @@ -159,7 +165,7 @@ dependencies { androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' androidTestImplementation 'org.amshove.kluent:kluent-android:1.44' - androidTestImplementation "io.mockk:mockk-android:1.8.13.kotlin13" + androidTestImplementation 'io.mockk:mockk-android:1.9.3.kotlin12' androidTestImplementation "androidx.arch.core:core-testing:$lifecycle_version" androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version" diff --git a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/InstrumentedTest.kt b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/InstrumentedTest.kt index c6db522c46..3cd47d4998 100644 --- a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/InstrumentedTest.kt +++ b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/InstrumentedTest.kt @@ -28,4 +28,4 @@ interface InstrumentedTest { fun cacheDir(): File { return context().cacheDir } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/OkReplayRuleChainNoActivity.kt b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/OkReplayRuleChainNoActivity.kt index 9fd1fe6b5c..098e927a9f 100644 --- a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/OkReplayRuleChainNoActivity.kt +++ b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/OkReplayRuleChainNoActivity.kt @@ -29,4 +29,4 @@ class OkReplayRuleChainNoActivity( return RuleChain.outerRule(PermissionRule(configuration)) .around(RecorderRule(configuration)) } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/SingleThreadCoroutineDispatcher.kt b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/SingleThreadCoroutineDispatcher.kt index 69803c5dc1..e63123f3b3 100644 --- a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/SingleThreadCoroutineDispatcher.kt +++ b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/SingleThreadCoroutineDispatcher.kt @@ -19,4 +19,4 @@ package im.vector.matrix.android import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers import kotlinx.coroutines.Dispatchers.Main -internal val testCoroutineDispatchers = MatrixCoroutineDispatchers(Main, Main, Main, Main, Main) \ No newline at end of file +internal val testCoroutineDispatchers = MatrixCoroutineDispatchers(Main, Main, Main, Main, Main) diff --git a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/auth/AuthenticatorTest.kt b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/auth/AuthenticatorTest.kt index 3dfc06196e..7d33fae4d8 100644 --- a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/auth/AuthenticatorTest.kt +++ b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/auth/AuthenticatorTest.kt @@ -28,7 +28,6 @@ import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith - @RunWith(AndroidJUnit4::class) internal class AuthenticatorTest : InstrumentedTest { @@ -50,7 +49,6 @@ internal class AuthenticatorTest : InstrumentedTest { @UiThreadTest @OkReplay(tape = "auth", mode = TapeMode.READ_WRITE) fun auth() { - } companion object { @@ -59,6 +57,4 @@ internal class AuthenticatorTest : InstrumentedTest { val grantExternalStoragePermissionRule: GrantPermissionRule = GrantPermissionRule.grant(android.Manifest.permission.WRITE_EXTERNAL_STORAGE) } - - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/internal/crypto/CryptoStoreHelper.kt b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/internal/crypto/CryptoStoreHelper.kt index c0fc6c4454..6b0ebbf6a4 100644 --- a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/internal/crypto/CryptoStoreHelper.kt +++ b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/internal/crypto/CryptoStoreHelper.kt @@ -41,4 +41,4 @@ internal class CryptoStoreHelper { refreshToken = null, deviceId = "deviceId_sample" ) -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/internal/crypto/CryptoStoreTest.kt b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/internal/crypto/CryptoStoreTest.kt index 0f65ad3ee5..3fc3079cc7 100644 --- a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/internal/crypto/CryptoStoreTest.kt +++ b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/internal/crypto/CryptoStoreTest.kt @@ -114,4 +114,4 @@ class CryptoStoreTest { olmAccount1.releaseAccount() olmAccount2.releaseAccount() } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/internal/util/JsonCanonicalizerTest.kt b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/internal/util/JsonCanonicalizerTest.kt index 1ea6105da4..0a7c8f6439 100644 --- a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/internal/util/JsonCanonicalizerTest.kt +++ b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/internal/util/JsonCanonicalizerTest.kt @@ -62,8 +62,6 @@ internal class JsonCanonicalizerTest : InstrumentedTest { JsonCanonicalizer.canonicalize("{\"a\":\"\\\"\"}")) } - - /* ========================================================================================== * Test from https://matrix.org/docs/spec/appendices.html#examples * ========================================================================================== */ @@ -74,7 +72,6 @@ internal class JsonCanonicalizerTest : InstrumentedTest { JsonCanonicalizer.canonicalize("""{}""")) } - @Test fun matrixOrg002Test() { assertEquals("""{"one":1,"two":"Two"}""", @@ -84,7 +81,6 @@ internal class JsonCanonicalizerTest : InstrumentedTest { }""")) } - @Test fun matrixOrg003Test() { assertEquals("""{"a":"1","b":"2"}""", @@ -94,14 +90,12 @@ internal class JsonCanonicalizerTest : InstrumentedTest { }""")) } - @Test fun matrixOrg004Test() { assertEquals("""{"a":"1","b":"2"}""", JsonCanonicalizer.canonicalize("""{"b":"2","a":"1"}""")) } - @Test fun matrixOrg005Test() { assertEquals("""{"auth":{"mxid":"@john.doe:example.com","profile":{"display_name":"John Doe","three_pids":[{"address":"john.doe@example.org","medium":"email"},{"address":"123456789","medium":"msisdn"}]},"success":true}}""", @@ -126,7 +120,6 @@ internal class JsonCanonicalizerTest : InstrumentedTest { }""")) } - @Test fun matrixOrg006Test() { assertEquals("""{"a":"日本語"}""", @@ -135,7 +128,6 @@ internal class JsonCanonicalizerTest : InstrumentedTest { }""")) } - @Test fun matrixOrg007Test() { assertEquals("""{"日":1,"本":2}""", @@ -145,7 +137,6 @@ internal class JsonCanonicalizerTest : InstrumentedTest { }""")) } - @Test fun matrixOrg008Test() { assertEquals("""{"a":"日"}""", @@ -159,4 +150,4 @@ internal class JsonCanonicalizerTest : InstrumentedTest { "a": null }""")) } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/session/room/timeline/ChunkEntityTest.kt b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/session/room/timeline/ChunkEntityTest.kt index c6da3c4628..abb990c979 100644 --- a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/session/room/timeline/ChunkEntityTest.kt +++ b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/session/room/timeline/ChunkEntityTest.kt @@ -35,7 +35,6 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith - @RunWith(AndroidJUnit4::class) internal class ChunkEntityTest : InstrumentedTest { @@ -48,7 +47,6 @@ internal class ChunkEntityTest : InstrumentedTest { monarchy = Monarchy.Builder().setRealmConfiguration(testConfig).build() } - @Test fun add_shouldAdd_whenNotAlreadyIncluded() { monarchy.runTransactionSync { realm -> @@ -194,5 +192,4 @@ internal class ChunkEntityTest : InstrumentedTest { chunk1.nextToken shouldEqual nextToken } } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/session/room/timeline/FakeGetContextOfEventTask.kt b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/session/room/timeline/FakeGetContextOfEventTask.kt index 48f223925c..0e1980f134 100644 --- a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/session/room/timeline/FakeGetContextOfEventTask.kt +++ b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/session/room/timeline/FakeGetContextOfEventTask.kt @@ -32,6 +32,4 @@ internal class FakeGetContextOfEventTask constructor(private val tokenChunkEvent ) return tokenChunkEventPersistor.insertInDb(tokenChunkEvent, params.roomId, PaginationDirection.BACKWARDS) } - - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/session/room/timeline/FakePaginationTask.kt b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/session/room/timeline/FakePaginationTask.kt index 2f7f63d77c..be67ffdbba 100644 --- a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/session/room/timeline/FakePaginationTask.kt +++ b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/session/room/timeline/FakePaginationTask.kt @@ -28,6 +28,4 @@ internal class FakePaginationTask @Inject constructor(private val tokenChunkEven val tokenChunkEvent = FakeTokenChunkEvent(params.from, Random.nextLong(System.currentTimeMillis()).toString(), fakeEvents) return tokenChunkEventPersistor.insertInDb(tokenChunkEvent, params.roomId, params.direction) } - } - diff --git a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/session/room/timeline/FakeTokenChunkEvent.kt b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/session/room/timeline/FakeTokenChunkEvent.kt index 2a9163e4ba..3f74df2c2e 100644 --- a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/session/room/timeline/FakeTokenChunkEvent.kt +++ b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/session/room/timeline/FakeTokenChunkEvent.kt @@ -23,4 +23,4 @@ internal data class FakeTokenChunkEvent(override val start: String?, override val end: String?, override val events: List = emptyList(), override val stateEvents: List = emptyList() -) : TokenChunkEvent \ No newline at end of file +) : TokenChunkEvent diff --git a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/session/room/timeline/RoomDataHelper.kt b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/session/room/timeline/RoomDataHelper.kt index 7ff693584e..8a8ee11854 100644 --- a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/session/room/timeline/RoomDataHelper.kt +++ b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/session/room/timeline/RoomDataHelper.kt @@ -88,6 +88,4 @@ object RoomDataHelper { roomEntity.addOrUpdate(chunkEntity) } } - - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/session/room/timeline/TimelineTest.kt b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/session/room/timeline/TimelineTest.kt index f09b037605..06651f9ba3 100644 --- a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/session/room/timeline/TimelineTest.kt +++ b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/session/room/timeline/TimelineTest.kt @@ -81,6 +81,4 @@ internal class TimelineTest : InstrumentedTest { // timelineEvents.size shouldEqual initialLoad + paginationCount // timeline.dispose() // } - - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/debug/java/im/vector/matrix/android/internal/network/interceptors/CurlLoggingInterceptor.kt b/matrix-sdk-android/src/debug/java/im/vector/matrix/android/internal/network/interceptors/CurlLoggingInterceptor.kt index 3d499be3c1..c96786ba3b 100644 --- a/matrix-sdk-android/src/debug/java/im/vector/matrix/android/internal/network/interceptors/CurlLoggingInterceptor.kt +++ b/matrix-sdk-android/src/debug/java/im/vector/matrix/android/internal/network/interceptors/CurlLoggingInterceptor.kt @@ -22,6 +22,7 @@ import okhttp3.Interceptor import okhttp3.Response import okhttp3.logging.HttpLoggingInterceptor import okio.Buffer +import timber.log.Timber import java.io.IOException import java.nio.charset.Charset import javax.inject.Inject @@ -51,27 +52,33 @@ internal class CurlLoggingInterceptor @Inject constructor(private val logger: Ht var compressed = false var curlCmd = "curl" - if (curlOptions != null) { - curlCmd += " " + curlOptions!! + curlOptions?.let { + curlCmd += " $it" } - curlCmd += " -X " + request.method() + curlCmd += " -X " + request.method - val requestBody = request.body() + val requestBody = request.body if (requestBody != null) { - val buffer = Buffer() - requestBody.writeTo(buffer) - var charset: Charset? = UTF8 - val contentType = requestBody.contentType() - if (contentType != null) { - charset = contentType.charset(UTF8) + if (requestBody.contentLength() > 100_000) { + Timber.w("Unable to log curl command data, size is too big (${requestBody.contentLength()})") + // Ensure the curl command will failed + curlCmd += "DATA IS TOO BIG" + } else { + val buffer = Buffer() + requestBody.writeTo(buffer) + var charset: Charset? = UTF8 + val contentType = requestBody.contentType() + if (contentType != null) { + charset = contentType.charset(UTF8) + } + // try to keep to a single line and use a subshell to preserve any line breaks + curlCmd += " --data $'" + buffer.readString(charset!!).replace("\n", "\\n") + "'" } - // try to keep to a single line and use a subshell to preserve any line breaks - curlCmd += " --data $'" + buffer.readString(charset!!).replace("\n", "\\n") + "'" } - val headers = request.headers() + val headers = request.headers var i = 0 - val count = headers.size() + val count = headers.size while (i < count) { val name = headers.name(i) val value = headers.value(i) @@ -82,7 +89,7 @@ internal class CurlLoggingInterceptor @Inject constructor(private val logger: Ht i++ } - curlCmd += ((if (compressed) " --compressed " else " ") + "'" + request.url().toString() + curlCmd += ((if (compressed) " --compressed " else " ") + "'" + request.url.toString() // Replace localhost for emulator by localhost for shell .replace("://10.0.2.2:8080/".toRegex(), "://127.0.0.1:8080/") + "'") @@ -90,7 +97,7 @@ internal class CurlLoggingInterceptor @Inject constructor(private val logger: Ht // Add Json formatting curlCmd += " | python -m json.tool" - logger.log("--- cURL (" + request.url() + ")") + logger.log("--- cURL (" + request.url + ")") logger.log(curlCmd) return chain.proceed(request) diff --git a/matrix-sdk-android/src/debug/java/im/vector/matrix/android/internal/network/interceptors/FormattedJsonHttpLogger.kt b/matrix-sdk-android/src/debug/java/im/vector/matrix/android/internal/network/interceptors/FormattedJsonHttpLogger.kt index 655134d1e3..43f1373daf 100644 --- a/matrix-sdk-android/src/debug/java/im/vector/matrix/android/internal/network/interceptors/FormattedJsonHttpLogger.kt +++ b/matrix-sdk-android/src/debug/java/im/vector/matrix/android/internal/network/interceptors/FormattedJsonHttpLogger.kt @@ -51,7 +51,6 @@ class FormattedJsonHttpLogger : HttpLoggingInterceptor.Logger { // Finally this is not a JSON string... Timber.e(e) } - } else if (message.startsWith("[")) { // JSON Array detected try { @@ -61,7 +60,6 @@ class FormattedJsonHttpLogger : HttpLoggingInterceptor.Logger { // Finally not JSON... Timber.e(e) } - } // Else not a json string to log } @@ -73,4 +71,4 @@ class FormattedJsonHttpLogger : HttpLoggingInterceptor.Logger { Timber.v(s) } } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/Matrix.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/Matrix.kt index bdc988d2f7..1bfa871a42 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/Matrix.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/Matrix.kt @@ -38,7 +38,6 @@ data class MatrixConfiguration( interface Provider { fun providesMatrixConfiguration(): MatrixConfiguration } - } /** @@ -98,5 +97,4 @@ class Matrix private constructor(context: Context, matrixConfiguration: MatrixCo return BuildConfig.VERSION_NAME + " (" + BuildConfig.GIT_SDK_REVISION + ")" } } - } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/MatrixCallback.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/MatrixCallback.kt index 00d22b1f9f..c2f70ce5dc 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/MatrixCallback.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/MatrixCallback.kt @@ -27,7 +27,7 @@ interface MatrixCallback { * @param data the data successfully returned from the async function */ fun onSuccess(data: T) { - //no-op + // no-op } /** @@ -35,7 +35,6 @@ interface MatrixCallback { * @param failure the failure data returned from the async function */ fun onFailure(failure: Throwable) { - //no-op + // no-op } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/MatrixPatterns.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/MatrixPatterns.kt index 935408296c..e30d139cd3 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/MatrixPatterns.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/MatrixPatterns.kt @@ -16,7 +16,6 @@ package im.vector.matrix.android.api - /** * This class contains pattern to match the different Matrix ids */ @@ -154,6 +153,5 @@ object MatrixPatterns { return if (index == -1) { null } else matrixId.substring(index + 1) - } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/auth/Authenticator.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/auth/Authenticator.kt index 2dc2d0ef5f..77a3cde249 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/auth/Authenticator.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/auth/Authenticator.kt @@ -68,4 +68,4 @@ interface Authenticator { * Create a session after a SSO successful login */ fun createSessionFromSso(credentials: Credentials, homeServerConnectionConfig: HomeServerConnectionConfig): Session -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/auth/data/HomeServerConnectionConfig.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/auth/data/HomeServerConnectionConfig.kt index 850c4f7186..e85b05092f 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/auth/data/HomeServerConnectionConfig.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/auth/data/HomeServerConnectionConfig.kt @@ -253,13 +253,5 @@ data class HomeServerConnectionConfig( forceUsageTlsVersions ) } - } - - } - - - - - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/comparators/DatedObjectComparators.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/comparators/DatedObjectComparators.kt index c9245e7331..a9d30f823c 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/comparators/DatedObjectComparators.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/comparators/DatedObjectComparators.kt @@ -37,4 +37,4 @@ object DatedObjectComparators { (datedObject2.date - datedObject1.date).toInt() } } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/extensions/MatrixSdkExtensions.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/extensions/MatrixSdkExtensions.kt index 180d80c5c5..685a522f60 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/extensions/MatrixSdkExtensions.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/extensions/MatrixSdkExtensions.kt @@ -19,7 +19,6 @@ package im.vector.matrix.android.api.extensions import im.vector.matrix.android.api.comparators.DatedObjectComparators import im.vector.matrix.android.internal.crypto.model.MXDeviceInfo import im.vector.matrix.android.internal.crypto.model.rest.DeviceInfo -import java.util.Collections /* ========================================================================================== * MXDeviceInfo @@ -29,7 +28,6 @@ fun MXDeviceInfo.getFingerprintHumanReadable() = fingerprint() ?.chunked(4) ?.joinToString(separator = " ") - -fun List.sortByLastSeen() { - Collections.sort(this, DatedObjectComparators.descComparator) -} \ No newline at end of file +fun MutableList.sortByLastSeen() { + sortWith(DatedObjectComparators.descComparator) +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/failure/ConsentNotGivenError.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/failure/ConsentNotGivenError.kt index c780720a18..80ee6811bb 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/failure/ConsentNotGivenError.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/failure/ConsentNotGivenError.kt @@ -19,4 +19,4 @@ package im.vector.matrix.android.api.failure // This data class will be sent to the bus data class ConsentNotGivenError( val consentUri: String -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/failure/Failure.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/failure/Failure.kt index 26170a288f..6c418ed831 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/failure/Failure.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/failure/Failure.kt @@ -42,5 +42,4 @@ sealed class Failure(cause: Throwable? = null) : Throwable(cause = cause) { data class CryptoError(val error: MXCryptoError) : Failure(error) abstract class FeatureFailure : Failure() - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/failure/MatrixError.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/failure/MatrixError.kt index 7d433ba7ba..70a982089c 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/failure/MatrixError.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/failure/MatrixError.kt @@ -33,7 +33,6 @@ data class MatrixError( @Json(name = "limit_type") val limitType: String? = null, @Json(name = "admin_contact") val adminUri: String? = null) { - companion object { const val FORBIDDEN = "M_FORBIDDEN" const val UNKNOWN = "M_UNKNOWN" @@ -64,4 +63,4 @@ data class MatrixError( // Possible value for "limit_type" const val LIMIT_TYPE_MAU = "monthly_active_user" } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/listeners/ProgressListener.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/listeners/ProgressListener.kt index 854f0e9fb6..ad47260f86 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/listeners/ProgressListener.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/listeners/ProgressListener.kt @@ -25,4 +25,4 @@ interface ProgressListener { * @param total */ fun onProgress(progress: Int, total: Int) -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/listeners/StepProgressListener.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/listeners/StepProgressListener.kt index af5b815c1a..196aa6d655 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/listeners/StepProgressListener.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/listeners/StepProgressListener.kt @@ -31,4 +31,4 @@ interface StepProgressListener { * @param step The current step, containing progress data if available. Else you should consider progress as indeterminate */ fun onStepProgress(step: Step) -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/permalinks/MatrixLinkify.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/permalinks/MatrixLinkify.kt index fb3dbcc26c..fc02cf4a61 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/permalinks/MatrixLinkify.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/permalinks/MatrixLinkify.kt @@ -30,9 +30,9 @@ object MatrixLinkify { * * @param spannable the text in which the matrix items has to be clickable. */ - fun addLinks(spannable: Spannable?, callback: MatrixPermalinkSpan.Callback?): Boolean { + fun addLinks(spannable: Spannable, callback: MatrixPermalinkSpan.Callback?): Boolean { // sanity checks - if (spannable.isNullOrEmpty()) { + if (spannable.isEmpty()) { return false } val text = spannable.toString() @@ -51,5 +51,4 @@ object MatrixLinkify { } return hasMatch } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/permalinks/MatrixPermalinkSpan.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/permalinks/MatrixPermalinkSpan.kt index 58cd76a0a6..afba5ab040 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/permalinks/MatrixPermalinkSpan.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/permalinks/MatrixPermalinkSpan.kt @@ -35,6 +35,4 @@ class MatrixPermalinkSpan(private val url: String, override fun onClick(widget: View) { callback?.onUrlClicked(url) } - - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/permalinks/PermalinkData.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/permalinks/PermalinkData.kt index 615892a107..47f8bf4505 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/permalinks/PermalinkData.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/permalinks/PermalinkData.kt @@ -33,5 +33,4 @@ sealed class PermalinkData { data class GroupLink(val groupId: String) : PermalinkData() data class FallbackLink(val uri: Uri) : PermalinkData() - } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/permalinks/PermalinkFactory.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/permalinks/PermalinkFactory.kt index 15d56eacb3..1af77869ee 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/permalinks/PermalinkFactory.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/permalinks/PermalinkFactory.kt @@ -16,7 +16,6 @@ package im.vector.matrix.android.api.permalinks -import android.text.TextUtils import im.vector.matrix.android.api.session.events.model.Event /** @@ -48,10 +47,9 @@ object PermalinkFactory { * @return the permalink, or null in case of error */ fun createPermalink(id: String): String? { - return if (TextUtils.isEmpty(id)) { + return if (id.isEmpty()) { null } else MATRIX_TO_URL_BASE + escape(id) - } /** @@ -72,16 +70,14 @@ object PermalinkFactory { * @param url the universal link, Ex: "https://matrix.to/#/@benoit:matrix.org" * @return the id from the url, ex: "@benoit:matrix.org", or null if the url is not a permalink */ - fun getLinkedId(url: String?): String? { - val isSupported = url != null && url.startsWith(MATRIX_TO_URL_BASE) + fun getLinkedId(url: String): String? { + val isSupported = url.startsWith(MATRIX_TO_URL_BASE) return if (isSupported) { - url!!.substring(MATRIX_TO_URL_BASE.length) + url.substring(MATRIX_TO_URL_BASE.length) } else null - } - /** * Escape '/' in id, because it is used as a separator * @@ -89,6 +85,6 @@ object PermalinkFactory { * @return the escaped id */ private fun escape(id: String): String { - return id.replace("/".toRegex(), "%2F") + return id.replace("/", "%2F") } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/permalinks/PermalinkParser.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/permalinks/PermalinkParser.kt index 71fd16e778..531f4ae523 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/permalinks/PermalinkParser.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/permalinks/PermalinkParser.kt @@ -72,5 +72,4 @@ object PermalinkParser { else -> PermalinkData.FallbackLink(uri) } } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/Action.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/Action.kt index b34d2d0d34..d135504055 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/Action.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/Action.kt @@ -18,7 +18,6 @@ package im.vector.matrix.android.api.pushrules import im.vector.matrix.android.api.pushrules.rest.PushRule import timber.log.Timber - sealed class Action { object Notify : Action() object DoNotNotify : Action() @@ -26,7 +25,6 @@ sealed class Action { data class Highlight(val highlight: Boolean) : Action() } - private const val ACTION_NOTIFY = "notify" private const val ACTION_DONT_NOTIFY = "dont_notify" private const val ACTION_COALESCE = "coalesce" @@ -80,7 +78,6 @@ fun PushRule.getActions(): List { } // When the value is not there, default sound (not specified by the spec) ?: Action.Sound(ACTION_OBJECT_VALUE_VALUE_DEFAULT) - } ACTION_OBJECT_SET_TWEAK_VALUE_HIGHLIGHT -> { (actionStrOrObj[ACTION_OBJECT_VALUE_KEY] as? Boolean)?.let { boolValue -> @@ -104,7 +101,5 @@ fun PushRule.getActions(): List { } } - return result } - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/Condition.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/Condition.kt index c0bb4f16f4..ecc78996db 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/Condition.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/Condition.kt @@ -35,9 +35,7 @@ abstract class Condition(val kind: Kind) { else -> UNRECOGNIZE } } - } - } abstract fun isSatisfied(conditionResolver: ConditionResolver): Boolean @@ -45,4 +43,4 @@ abstract class Condition(val kind: Kind) { open fun technicalDescription(): String { return "Kind: $kind" } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/ConditionResolver.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/ConditionResolver.kt index 4d15d5deec..340810bc80 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/ConditionResolver.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/ConditionResolver.kt @@ -25,4 +25,4 @@ interface ConditionResolver { fun resolveRoomMemberCountCondition(roomMemberCountCondition: RoomMemberCountCondition): Boolean fun resolveSenderNotificationPermissionCondition(senderNotificationPermissionCondition: SenderNotificationPermissionCondition): Boolean fun resolveContainsDisplayNameCondition(containsDisplayNameCondition: ContainsDisplayNameCondition) : Boolean -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/ContainsDisplayNameCondition.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/ContainsDisplayNameCondition.kt index 37bc75ad57..166ec4f05f 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/ContainsDisplayNameCondition.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/ContainsDisplayNameCondition.kt @@ -15,13 +15,11 @@ */ package im.vector.matrix.android.api.pushrules -import android.text.TextUtils import im.vector.matrix.android.api.session.events.model.Event import im.vector.matrix.android.api.session.events.model.EventType import im.vector.matrix.android.api.session.events.model.toModel import im.vector.matrix.android.api.session.room.model.message.MessageContent import timber.log.Timber -import java.util.regex.Pattern class ContainsDisplayNameCondition : Condition(Kind.contains_display_name) { @@ -34,11 +32,11 @@ class ContainsDisplayNameCondition : Condition(Kind.contains_display_name) { } fun isSatisfied(event: Event, displayName: String): Boolean { - var message = when (event.type) { + val message = when (event.type) { EventType.MESSAGE -> { event.content.toModel() } - //TODO the spec says: + // TODO the spec says: // Matches any message whose content is unencrypted and contains the user's current display name // EventType.ENCRYPTED -> { // event.root.getClearContent()?.toModel() @@ -49,7 +47,6 @@ class ContainsDisplayNameCondition : Condition(Kind.contains_display_name) { return caseInsensitiveFind(displayName, message.body) } - companion object { /** * Returns whether a string contains an occurrence of another, as a standalone word, regardless of case. @@ -60,20 +57,18 @@ class ContainsDisplayNameCondition : Condition(Kind.contains_display_name) { */ fun caseInsensitiveFind(subString: String, longString: String): Boolean { // add sanity checks - if (TextUtils.isEmpty(subString) || TextUtils.isEmpty(longString)) { + if (subString.isEmpty() || longString.isEmpty()) { return false } - var res = false - try { - val pattern = Pattern.compile("(\\W|^)" + Pattern.quote(subString) + "(\\W|$)", Pattern.CASE_INSENSITIVE) - res = pattern.matcher(longString).find() + val regex = Regex("(\\W|^)" + Regex.escape(subString) + "(\\W|$)", RegexOption.IGNORE_CASE) + return regex.containsMatchIn(longString) } catch (e: Exception) { Timber.e(e, "## caseInsensitiveFind() : failed") } - return res + return false } } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/EventMatchCondition.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/EventMatchCondition.kt index 7325abba2a..a4eacc9018 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/EventMatchCondition.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/EventMatchCondition.kt @@ -29,28 +29,25 @@ class EventMatchCondition(val key: String, val pattern: String) : Condition(Kind return "'$key' Matches '$pattern'" } - fun isSatisfied(event: Event): Boolean { - //TODO encrypted events? + // TODO encrypted events? val rawJson = MoshiProvider.providesMoshi().adapter(Event::class.java).toJsonValue(event) as? Map<*, *> ?: return false val value = extractField(rawJson, key) ?: return false - //Patterns with no special glob characters should be treated as having asterisks prepended + // Patterns with no special glob characters should be treated as having asterisks prepended // and appended when testing the condition. try { val modPattern = if (hasSpecialGlobChar(pattern)) simpleGlobToRegExp(pattern) else simpleGlobToRegExp("*$pattern*") val regex = Regex(modPattern, RegexOption.DOT_MATCHES_ALL) return regex.containsMatchIn(value) } catch (e: Throwable) { - //e.g PatternSyntaxException + // e.g PatternSyntaxException Timber.e(e, "Failed to evaluate push condition") return false } - } - private fun extractField(jsonObject: Map<*, *>, fieldPath: String): String? { val fieldParts = fieldPath.split(".") if (fieldParts.isEmpty()) return null @@ -77,9 +74,9 @@ class EventMatchCondition(val key: String, val pattern: String) : Condition(Kind return glob.contains("*") || glob.contains("?") } - //Very simple glob to regexp converter + // Very simple glob to regexp converter private fun simpleGlobToRegExp(glob: String): String { - var out = ""//"^" + var out = "" // "^" for (i in 0 until glob.length) { val c = glob[i] when (c) { @@ -90,8 +87,8 @@ class EventMatchCondition(val key: String, val pattern: String) : Condition(Kind else -> out += c } } - out += ""//'$'.toString() + out += "" // '$'.toString() return out } } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/PushRuleService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/PushRuleService.kt index c0204d181d..aa277ea8bd 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/PushRuleService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/PushRuleService.kt @@ -27,10 +27,10 @@ interface PushRuleService { */ fun fetchPushRules(scope: String = RuleScope.GLOBAL) - //TODO get push rule set + // TODO get push rule set fun getPushRules(scope: String = RuleScope.GLOBAL): List - //TODO update rule + // TODO update rule fun updatePushRuleEnableStatus(kind: RuleKind, pushRule: PushRule, enabled: Boolean, callback: MatrixCallback): Cancelable @@ -42,8 +42,9 @@ interface PushRuleService { interface PushRuleListener { fun onMatchRule(event: Event, actions: List) + fun onRoomJoined(roomId: String) fun onRoomLeft(roomId: String) fun onEventRedacted(redactedEventId: String) fun batchFinish() } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/RoomMemberCountCondition.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/RoomMemberCountCondition.kt index d0b76fbab7..d41788234b 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/RoomMemberCountCondition.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/RoomMemberCountCondition.kt @@ -62,6 +62,5 @@ class RoomMemberCountCondition(val iz: String) : Condition(Kind.room_member_coun Timber.d(t) } return null - } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/SenderNotificationPermissionCondition.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/SenderNotificationPermissionCondition.kt index 35b731c5c3..46fc9a5c6d 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/SenderNotificationPermissionCondition.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/SenderNotificationPermissionCondition.kt @@ -18,7 +18,6 @@ package im.vector.matrix.android.api.pushrules import im.vector.matrix.android.api.session.events.model.Event import im.vector.matrix.android.api.session.room.model.PowerLevels - class SenderNotificationPermissionCondition(val key: String) : Condition(Kind.sender_notification_permission) { override fun isSatisfied(conditionResolver: ConditionResolver): Boolean { @@ -29,8 +28,7 @@ class SenderNotificationPermissionCondition(val key: String) : Condition(Kind.se return "User power level <$key>" } - fun isSatisfied(event: Event, powerLevels: PowerLevels): Boolean { return event.senderId != null && powerLevels.getUserPowerLevel(event.senderId) >= powerLevels.notificationLevel(key) } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/rest/PushCondition.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/rest/PushCondition.kt index 7b71a344a0..4b643a0b42 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/rest/PushCondition.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/rest/PushCondition.kt @@ -76,4 +76,4 @@ data class PushCondition( } } } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/rest/PushRule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/rest/PushRule.kt index 1e36a0d867..e9423d7c40 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/rest/PushRule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/rest/PushRule.kt @@ -19,7 +19,6 @@ package im.vector.matrix.android.api.pushrules.rest import com.squareup.moshi.Json import com.squareup.moshi.JsonClass - @JsonClass(generateAdapter = true) data class PushRule( /** @@ -47,4 +46,3 @@ data class PushRule( */ val pattern: String? = null ) - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/rest/Ruleset.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/rest/Ruleset.kt index 5f4ca15ac0..72692d5afd 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/rest/Ruleset.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/rest/Ruleset.kt @@ -24,4 +24,4 @@ data class Ruleset( val room: List? = null, val sender: List? = null, val underride: List? = null -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/InitialSyncProgressService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/InitialSyncProgressService.kt index a4c9d81beb..4d65179307 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/InitialSyncProgressService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/InitialSyncProgressService.kt @@ -26,4 +26,4 @@ interface InitialSyncProgressService { @StringRes val statusText: Int, val percentProgress: Int = 0 ) -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/Session.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/Session.kt index 53dc8e77a0..2440713a40 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/Session.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/Session.kt @@ -19,6 +19,7 @@ package im.vector.matrix.android.api.session import androidx.annotation.MainThread import androidx.lifecycle.LiveData import im.vector.matrix.android.api.auth.data.SessionParams +import im.vector.matrix.android.api.failure.ConsentNotGivenError import im.vector.matrix.android.api.pushrules.PushRuleService import im.vector.matrix.android.api.session.cache.CacheService import im.vector.matrix.android.api.session.content.ContentUploadStateTracker @@ -26,6 +27,7 @@ import im.vector.matrix.android.api.session.content.ContentUrlResolver import im.vector.matrix.android.api.session.crypto.CryptoService import im.vector.matrix.android.api.session.file.FileService import im.vector.matrix.android.api.session.group.GroupService +import im.vector.matrix.android.api.session.homeserver.HomeServerCapabilitiesService import im.vector.matrix.android.api.session.pushers.PushersService import im.vector.matrix.android.api.session.room.RoomDirectoryService import im.vector.matrix.android.api.session.room.RoomService @@ -52,6 +54,7 @@ interface Session : PushRuleService, PushersService, InitialSyncProgressService, + HomeServerCapabilitiesService, SecureStorageService { /** @@ -65,7 +68,6 @@ interface Session : val myUserId: String get() = sessionParams.credentials.userId - /** * This method allow to open a session. It does start some service on the background. */ @@ -138,6 +140,9 @@ interface Session : */ fun onInvalidToken() + /** + * A M_CONSENT_NOT_GIVEN error has been received from the homeserver + */ + fun onConsentNotGivenError(consentNotGivenError: ConsentNotGivenError) } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/cache/CacheService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/cache/CacheService.kt index 43ab78b5aa..f1e4ca6c7b 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/cache/CacheService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/cache/CacheService.kt @@ -27,5 +27,4 @@ interface CacheService { * Clear the whole cached data, except credentials. Once done, the session is closed and has to be opened again */ fun clearCache(callback: MatrixCallback) - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/content/ContentAttachmentData.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/content/ContentAttachmentData.kt index c8dca8692c..933657b2fb 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/content/ContentAttachmentData.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/content/ContentAttachmentData.kt @@ -17,6 +17,7 @@ package im.vector.matrix.android.api.session.content import android.os.Parcelable +import androidx.exifinterface.media.ExifInterface import kotlinx.android.parcel.Parcelize @Parcelize @@ -26,6 +27,7 @@ data class ContentAttachmentData( val date: Long = 0, val height: Long? = 0, val width: Long? = 0, + val exifOrientation: Int = ExifInterface.ORIENTATION_UNDEFINED, val name: String? = null, val path: String, val mimeType: String, @@ -38,5 +40,4 @@ data class ContentAttachmentData( AUDIO, VIDEO } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/content/ContentUploadStateTracker.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/content/ContentUploadStateTracker.kt index 26273ebb8a..540b164aa5 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/content/ContentUploadStateTracker.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/content/ContentUploadStateTracker.kt @@ -35,4 +35,4 @@ interface ContentUploadStateTracker { object Success : State() data class Failure(val throwable: Throwable) : State() } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/content/ContentUrlResolver.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/content/ContentUrlResolver.kt index 0a20bef809..9ba1631aec 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/content/ContentUrlResolver.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/content/ContentUrlResolver.kt @@ -44,4 +44,4 @@ interface ContentUrlResolver { * @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? -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/CryptoService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/CryptoService.kt index 43c783a13d..706f89dfc9 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/CryptoService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/CryptoService.kt @@ -112,5 +112,4 @@ interface CryptoService { fun addNewSessionListener(newSessionListener: NewSessionListener) fun removeSessionListener(listener: NewSessionListener) - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/MXCryptoError.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/MXCryptoError.kt index b61a1e4149..fe41b6c074 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/MXCryptoError.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/MXCryptoError.kt @@ -90,4 +90,4 @@ sealed class MXCryptoError : Throwable() { const val NO_MORE_ALGORITHM_REASON = "Room was previously configured to use encryption, but is no longer." + " Perhaps the homeserver is hiding the configuration event." } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/keysbackup/KeysBackupService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/keysbackup/KeysBackupService.kt index 6728daa527..cb06dbf665 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/keysbackup/KeysBackupService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/keysbackup/KeysBackupService.kt @@ -210,5 +210,4 @@ interface KeysBackupService { val isEnabled: Boolean val isStucked: Boolean val state: KeysBackupState - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/keysbackup/KeysBackupState.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/keysbackup/KeysBackupState.kt index a1bd29e78d..a20f1c61b4 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/keysbackup/KeysBackupState.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/keysbackup/KeysBackupState.kt @@ -72,4 +72,4 @@ enum class KeysBackupState { WillBackUp, // e2e keys are being sent to the homeserver BackingUp -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/keysbackup/KeysBackupStateListener.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/keysbackup/KeysBackupStateListener.kt index f145d779f1..be1f2e5f3e 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/keysbackup/KeysBackupStateListener.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/keysbackup/KeysBackupStateListener.kt @@ -23,4 +23,4 @@ interface KeysBackupStateListener { * @param newState the new state */ fun onStateChange(newState: KeysBackupState) -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/sas/CancelCode.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/sas/CancelCode.kt index d999d06fc5..92a69bcad6 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/sas/CancelCode.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/sas/CancelCode.kt @@ -30,4 +30,4 @@ enum class CancelCode(val value: String, val humanReadable: String) { fun safeValueOf(code: String?): CancelCode { return CancelCode.values().firstOrNull { code == it.value } ?: CancelCode.User -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/sas/EmojiRepresentation.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/sas/EmojiRepresentation.kt index 0bcb96a999..031610f0c6 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/sas/EmojiRepresentation.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/sas/EmojiRepresentation.kt @@ -19,4 +19,4 @@ package im.vector.matrix.android.api.session.crypto.sas import androidx.annotation.StringRes data class EmojiRepresentation(val emoji: String, - @StringRes val nameResId: Int) \ No newline at end of file + @StringRes val nameResId: Int) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/sas/IncomingSasVerificationTransaction.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/sas/IncomingSasVerificationTransaction.kt index 791c63dc15..57dfc74236 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/sas/IncomingSasVerificationTransaction.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/sas/IncomingSasVerificationTransaction.kt @@ -31,4 +31,4 @@ interface IncomingSasVerificationTransaction { CANCELLED_BY_ME, CANCELLED_BY_OTHER } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/sas/OutgoingSasVerificationRequest.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/sas/OutgoingSasVerificationRequest.kt index 6aeed55549..f2c16da997 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/sas/OutgoingSasVerificationRequest.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/sas/OutgoingSasVerificationRequest.kt @@ -29,4 +29,4 @@ interface OutgoingSasVerificationRequest { CANCELLED_BY_ME, CANCELLED_BY_OTHER } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/sas/Mode.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/sas/SasMode.kt similarity index 99% rename from matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/sas/Mode.kt rename to matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/sas/SasMode.kt index da72e98bad..f58485decd 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/sas/Mode.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/sas/SasMode.kt @@ -19,4 +19,4 @@ package im.vector.matrix.android.api.session.crypto.sas object SasMode { const val DECIMAL = "decimal" const val EMOJI = "emoji" -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/sas/SasVerificationService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/sas/SasVerificationService.kt index a11c69cd7e..88c0787b4d 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/sas/SasVerificationService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/sas/SasVerificationService.kt @@ -36,4 +36,4 @@ interface SasVerificationService { fun transactionUpdated(tx: SasVerificationTransaction) fun markedAsManuallyVerified(userId: String, deviceId: String) } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/sas/SasVerificationTransaction.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/sas/SasVerificationTransaction.kt index dc489cf644..d24ccadb55 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/sas/SasVerificationTransaction.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/sas/SasVerificationTransaction.kt @@ -47,4 +47,4 @@ interface SasVerificationTransaction { * both short codes do match */ fun userHasVerifiedShortCode() -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/sas/SasVerificationTxState.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/sas/SasVerificationTxState.kt index 60ce8f0cc6..350ec2c381 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/sas/SasVerificationTxState.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/sas/SasVerificationTxState.kt @@ -43,7 +43,7 @@ enum class SasVerificationTxState { Verifying, Verified, - //Global: The verification has been cancelled (by me or other), see cancelReason for details + // Global: The verification has been cancelled (by me or other), see cancelReason for details Cancelled, OnCancelled } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/events/model/AggregatedAnnotation.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/events/model/AggregatedAnnotation.kt index 3f1c619906..ef164cd17b 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/events/model/AggregatedAnnotation.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/events/model/AggregatedAnnotation.kt @@ -34,9 +34,9 @@ import com.squareup.moshi.JsonClass */ @JsonClass(generateAdapter = true) -data class AggregatedAnnotation ( +data class AggregatedAnnotation( override val limited: Boolean? = false, override val count: Int? = 0, val chunk: List? = null -) : UnsignedRelationInfo \ No newline at end of file +) : UnsignedRelationInfo diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/events/model/AggregatedRelations.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/events/model/AggregatedRelations.kt index 0f8d21f532..d04a72bac5 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/events/model/AggregatedRelations.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/events/model/AggregatedRelations.kt @@ -50,4 +50,4 @@ import com.squareup.moshi.JsonClass data class AggregatedRelations( @Json(name = "m.annotation") val annotations: AggregatedAnnotation? = null, @Json(name = "m.reference") val references: DefaultUnsignedRelationInfo? = null -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/events/model/DefaultUnsignedRelationInfo.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/events/model/DefaultUnsignedRelationInfo.kt index 3e2df0aaf2..f7a573ca28 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/events/model/DefaultUnsignedRelationInfo.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/events/model/DefaultUnsignedRelationInfo.kt @@ -23,4 +23,4 @@ data class DefaultUnsignedRelationInfo( override val count: Int? = 0, val chunk: List>? = null -) : UnsignedRelationInfo \ No newline at end of file +) : UnsignedRelationInfo diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/events/model/Event.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/events/model/Event.kt index 902515a239..bc6885eddc 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/events/model/Event.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/events/model/Event.kt @@ -16,7 +16,6 @@ package im.vector.matrix.android.api.session.events.model -import android.text.TextUtils import com.squareup.moshi.Json import com.squareup.moshi.JsonClass import im.vector.matrix.android.api.session.crypto.MXCryptoError @@ -35,18 +34,16 @@ typealias Content = JsonDict * This methods is a facility method to map a json content to a model. */ inline fun Content?.toModel(catchError: Boolean = true): T? { - return this?.let { - val moshi = MoshiProvider.providesMoshi() - val moshiAdapter = moshi.adapter(T::class.java) - return try { - moshiAdapter.fromJsonValue(it) - } catch (e: Exception) { - if (catchError) { - Timber.e(e, "To model failed : $e") - null - } else { - throw e - } + val moshi = MoshiProvider.providesMoshi() + val moshiAdapter = moshi.adapter(T::class.java) + return try { + moshiAdapter.fromJsonValue(this) + } catch (e: Exception) { + if (catchError) { + Timber.e(e, "To model failed : $e") + null + } else { + throw e } } } @@ -55,12 +52,10 @@ inline fun Content?.toModel(catchError: Boolean = true): T? { * This methods is a facility method to map a model to a json Content */ @Suppress("UNCHECKED_CAST") -inline fun T?.toContent(): Content? { - return this?.let { - val moshi = MoshiProvider.providesMoshi() - val moshiAdapter = moshi.adapter(T::class.java) - return moshiAdapter.toJsonValue(it) as Content - } +inline fun T.toContent(): Content { + val moshi = MoshiProvider.providesMoshi() + val moshiAdapter = moshi.adapter(T::class.java) + return moshiAdapter.toJsonValue(this) as Content } /** @@ -81,7 +76,6 @@ data class Event( @Json(name = "redacts") val redacts: String? = null ) { - @Transient var mxDecryptionResult: OlmDecryptionResult? = null @@ -91,7 +85,6 @@ data class Event( @Transient var sendState: SendState = SendState.UNKNOWN - /** * Check if event is a state event. * @return true if event is state event. @@ -100,15 +93,15 @@ data class Event( return EventType.isStateEvent(getClearType()) } - //============================================================================================================== + // ============================================================================================================== // Crypto - //============================================================================================================== + // ============================================================================================================== /** * @return true if this event is encrypted. */ fun isEncrypted(): Boolean { - return TextUtils.equals(type, EventType.ENCRYPTED) + return type == EventType.ENCRYPTED } /** @@ -136,11 +129,12 @@ data class Event( * @return the event content */ fun getClearContent(): Content? { + @Suppress("UNCHECKED_CAST") return mxDecryptionResult?.payload?.get("content") as? Content ?: content } fun toContentStringWithIndent(): String { - val contentMap = toContent()?.toMutableMap() ?: HashMap() + val contentMap = toContent().toMutableMap() return JSONObject(contentMap).toString(4) } @@ -194,10 +188,8 @@ data class Event( result = 31 * result + sendState.hashCode() return result } - } - fun Event.isTextMessage(): Boolean { return getClearType() == EventType.MESSAGE && when (getClearContent()?.toModel()?.type) { @@ -214,4 +206,4 @@ fun Event.isImageMessage(): Boolean { MessageType.MSGTYPE_IMAGE -> true else -> false } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/events/model/EventType.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/events/model/EventType.kt index 98ce6c0f9e..38c24fa89b 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/events/model/EventType.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/events/model/EventType.kt @@ -16,7 +16,6 @@ package im.vector.matrix.android.api.session.events.model - /** * Constants defining known event types from Matrix specifications. */ @@ -93,7 +92,6 @@ object EventType { STATE_PINNED_EVENT ) - fun isStateEvent(type: String): Boolean { return STATE_EVENTS.contains(type) } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/events/model/LocalEcho.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/events/model/LocalEcho.kt new file mode 100644 index 0000000000..ca75871cda --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/events/model/LocalEcho.kt @@ -0,0 +1,28 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.matrix.android.api.session.events.model + +import java.util.* + +object LocalEcho { + + private const val PREFIX = "local." + + fun isLocalEchoId(eventId: String) = eventId.startsWith(PREFIX) + + fun createLocalEchoId() = "${PREFIX}${UUID.randomUUID()}" +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/events/model/RelationType.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/events/model/RelationType.kt index 0f5421a05a..06b3e9bf2e 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/events/model/RelationType.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/events/model/RelationType.kt @@ -15,7 +15,6 @@ */ package im.vector.matrix.android.api.session.events.model - /** * Constants defining known event relation types from Matrix specifications */ @@ -27,5 +26,4 @@ object RelationType { const val REPLACE = "m.replace" /** Lets you define an event which references an existing event.*/ const val REFERENCE = "m.reference" - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/events/model/UnsignedData.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/events/model/UnsignedData.kt index 4a9547e3f1..57eaa7dc76 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/events/model/UnsignedData.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/events/model/UnsignedData.kt @@ -26,4 +26,4 @@ data class UnsignedData( @Json(name = "transaction_id") val transactionId: String? = null, @Json(name = "prev_content") val prevContent: Map? = null, @Json(name = "m.relations") val relations: AggregatedRelations? = null -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/events/model/UnsignedRelationInfo.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/events/model/UnsignedRelationInfo.kt index 5b627b6236..ad31ad3a32 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/events/model/UnsignedRelationInfo.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/events/model/UnsignedRelationInfo.kt @@ -15,8 +15,7 @@ */ package im.vector.matrix.android.api.session.events.model - interface UnsignedRelationInfo { val limited : Boolean? val count: Int? -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/file/FileService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/file/FileService.kt index 296b7e1537..e1694199ed 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/file/FileService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/file/FileService.kt @@ -20,7 +20,6 @@ import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.internal.crypto.attachments.ElementToDecrypt import java.io.File - /** * This interface defines methods to get files. */ @@ -49,4 +48,4 @@ interface FileService { url: String?, elementToDecrypt: ElementToDecrypt?, callback: MatrixCallback) -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/group/Group.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/group/Group.kt index ae41eb9eb7..3967c15704 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/group/Group.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/group/Group.kt @@ -21,4 +21,4 @@ package im.vector.matrix.android.api.session.group */ interface Group { val groupId: String -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/group/GroupService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/group/GroupService.kt index 2ccfbff2c7..ff63d1a9e7 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/group/GroupService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/group/GroupService.kt @@ -19,7 +19,6 @@ package im.vector.matrix.android.api.session.group import androidx.lifecycle.LiveData import im.vector.matrix.android.api.session.group.model.GroupSummary - /** * This interface defines methods to get groups. It's implemented at the session level. */ @@ -37,4 +36,4 @@ interface GroupService { * @return the [LiveData] of [GroupSummary] */ fun liveGroupSummaries(): LiveData> -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/group/model/GroupSummary.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/group/model/GroupSummary.kt index 328ca746a6..8e39d6d31a 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/group/model/GroupSummary.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/group/model/GroupSummary.kt @@ -30,4 +30,4 @@ data class GroupSummary( val avatarUrl: String = "", val roomIds: List = emptyList(), val userIds: List = emptyList() -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/homeserver/HomeServerCapabilities.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/homeserver/HomeServerCapabilities.kt new file mode 100644 index 0000000000..9b01cdef3b --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/homeserver/HomeServerCapabilities.kt @@ -0,0 +1,28 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.matrix.android.api.session.homeserver + +data class HomeServerCapabilities( + /** + * Max size of file which can be uploaded to the homeserver in bytes. [MAX_UPLOAD_FILE_SIZE_UNKNOWN] if unknown or not retrieved yet + */ + val maxUploadFileSize: Long = MAX_UPLOAD_FILE_SIZE_UNKNOWN +) { + companion object { + const val MAX_UPLOAD_FILE_SIZE_UNKNOWN = -1L + } +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/homeserver/HomeServerCapabilitiesService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/homeserver/HomeServerCapabilitiesService.kt new file mode 100644 index 0000000000..e8b38735cf --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/homeserver/HomeServerCapabilitiesService.kt @@ -0,0 +1,28 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.matrix.android.api.session.homeserver + +/** + * This interface defines a method to retrieve the homeserver capabilities. + */ +interface HomeServerCapabilitiesService { + + /** + * Get the HomeServer capabilities + */ + fun getHomeServerCapabilities(): HomeServerCapabilities +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/pushers/Pusher.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/pushers/Pusher.kt index baedce9693..ba0af7d4dc 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/pushers/Pusher.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/pushers/Pusher.kt @@ -39,4 +39,4 @@ enum class PusherState { data class PusherData( val url: String? = null, val format: String? = null -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/pushers/PushersService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/pushers/PushersService.kt index c905490432..d082faa7c7 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/pushers/PushersService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/pushers/PushersService.kt @@ -19,7 +19,6 @@ import androidx.lifecycle.LiveData import im.vector.matrix.android.api.MatrixCallback import java.util.UUID - interface PushersService { /** @@ -53,7 +52,6 @@ interface PushersService { append: Boolean, withEventIdOnly: Boolean): UUID - fun removeHttpPusher(pushkey: String, appId: String, callback: MatrixCallback) companion object { @@ -63,4 +61,4 @@ interface PushersService { fun livePushers(): LiveData> fun pushers() : List -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/Room.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/Room.kt index 92414eb768..70c9c6e36c 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/Room.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/Room.kt @@ -21,11 +21,13 @@ import im.vector.matrix.android.api.session.room.crypto.RoomCryptoService import im.vector.matrix.android.api.session.room.members.MembershipService import im.vector.matrix.android.api.session.room.model.RoomSummary import im.vector.matrix.android.api.session.room.model.relation.RelationService +import im.vector.matrix.android.api.session.room.reporting.ReportingService import im.vector.matrix.android.api.session.room.read.ReadService import im.vector.matrix.android.api.session.room.send.DraftService import im.vector.matrix.android.api.session.room.send.SendService import im.vector.matrix.android.api.session.room.state.StateService import im.vector.matrix.android.api.session.room.timeline.TimelineService +import im.vector.matrix.android.api.util.Optional /** * This interface defines methods to interact within a room. @@ -37,6 +39,7 @@ interface Room : ReadService, MembershipService, StateService, + ReportingService, RelationService, RoomCryptoService { @@ -49,8 +52,7 @@ interface Room : * A live [RoomSummary] associated with the room * You can observe this summary to get dynamic data from this room. */ - fun liveRoomSummary(): LiveData + fun getRoomSummaryLive(): LiveData> fun roomSummary(): RoomSummary? - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/RoomDirectoryService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/RoomDirectoryService.kt index 272ab5675b..930320d976 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/RoomDirectoryService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/RoomDirectoryService.kt @@ -42,5 +42,4 @@ interface RoomDirectoryService { * Includes both the available protocols and all fields required for queries against each protocol. */ fun getThirdPartyProtocol(callback: MatrixCallback>): Cancelable - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/RoomService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/RoomService.kt index 7ec50bd2ca..c7fedb2627 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/RoomService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/RoomService.kt @@ -54,4 +54,8 @@ interface RoomService { */ fun liveRoomSummaries(): LiveData> -} \ No newline at end of file + /** + * Mark all rooms as read + */ + fun markAllAsRead(roomIds: List, callback: MatrixCallback): Cancelable +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/crypto/RoomCryptoService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/crypto/RoomCryptoService.kt index 910002ab6e..f8c15fde47 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/crypto/RoomCryptoService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/crypto/RoomCryptoService.kt @@ -23,4 +23,4 @@ interface RoomCryptoService { fun encryptionAlgorithm(): String? fun shouldEncryptForInvitedMembers(): Boolean -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/failure/CreateRoomFailure.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/failure/CreateRoomFailure.kt index 086dc621ca..263f699e62 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/failure/CreateRoomFailure.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/failure/CreateRoomFailure.kt @@ -21,5 +21,4 @@ import im.vector.matrix.android.api.failure.Failure sealed class CreateRoomFailure : Failure.FeatureFailure() { object CreatedWithTimeout: CreateRoomFailure() - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/failure/JoinRoomFailure.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/failure/JoinRoomFailure.kt index 4c7dd62ad6..80393e5d3d 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/failure/JoinRoomFailure.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/failure/JoinRoomFailure.kt @@ -21,5 +21,4 @@ import im.vector.matrix.android.api.failure.Failure sealed class JoinRoomFailure : Failure.FeatureFailure() { object JoinedWithTimeout : JoinRoomFailure() - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/members/MembershipService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/members/MembershipService.kt index 9dba26cb3e..8d60bee9da 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/members/MembershipService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/members/MembershipService.kt @@ -64,5 +64,4 @@ interface MembershipService { * Leave the room, or reject an invitation. */ fun leave(callback: MatrixCallback): Cancelable - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/EventAnnotationsSummary.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/EventAnnotationsSummary.kt index 18899f8700..0d403be2f4 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/EventAnnotationsSummary.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/EventAnnotationsSummary.kt @@ -19,4 +19,4 @@ data class EventAnnotationsSummary( var eventId: String, var reactionsSummary: List, var editSummary: EditAggregatedSummary? -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/Invite.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/Invite.kt index c808ad556c..c439143de5 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/Invite.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/Invite.kt @@ -27,4 +27,4 @@ data class Invite( @Json(name = "display_name") val displayName: String, @Json(name = "signed") val signed: Signed -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/Membership.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/Membership.kt index d87bb9b3db..1894effc7a 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/Membership.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/Membership.kt @@ -43,5 +43,4 @@ enum class Membership(val value: String) { fun isLeft(): Boolean { return this == KNOCK || this == LEAVE || this == BAN } - } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/PowerLevels.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/PowerLevels.kt index 964d618264..27f7820156 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/PowerLevels.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/PowerLevels.kt @@ -16,11 +16,9 @@ package im.vector.matrix.android.api.session.room.model -import android.text.TextUtils import com.squareup.moshi.Json import com.squareup.moshi.JsonClass import im.vector.matrix.android.api.session.events.model.EventType -import java.util.* /** * Class representing the EventType.EVENT_TYPE_STATE_ROOM_POWER_LEVELS state event content. @@ -45,14 +43,8 @@ data class PowerLevels( * @param userId the user id * @return the power level */ - fun getUserPowerLevel(userId: String): Int { - // sanity check - if (!TextUtils.isEmpty(userId)) { - val powerLevel = users[userId] - return powerLevel ?: usersDefault - } - - return usersDefault + fun getUserPowerLevel(userId: String): Int { + return users.getOrElse(userId) { usersDefault } } /** @@ -61,10 +53,8 @@ data class PowerLevels( * @param userId the user * @param powerLevel the new power level */ - fun setUserPowerLevel(userId: String?, powerLevel: Int) { - if (null != userId) { - users[userId] = Integer.valueOf(powerLevel) - } + fun setUserPowerLevel(userId: String, powerLevel: Int) { + users[userId] = powerLevel } /** @@ -74,11 +64,10 @@ data class PowerLevels( * @param userId the user id * @return true if the user can send the event */ - fun maySendEventOfType(eventTypeString: String, userId: String): Boolean { - return if (!TextUtils.isEmpty(eventTypeString) && !TextUtils.isEmpty(userId)) { + fun maySendEventOfType(eventTypeString: String, userId: String): Boolean { + return if (eventTypeString.isNotEmpty() && userId.isNotEmpty()) { getUserPowerLevel(userId) >= minimumPowerLevelForSendingEventAsMessage(eventTypeString) } else false - } /** @@ -87,8 +76,8 @@ data class PowerLevels( * @param userId the user id * @return true if the user can send a room message */ - fun maySendMessage(userId: String): Boolean { - return maySendEventOfType(EventType.MESSAGE, userId) + fun maySendMessage(userId: String): Boolean { + return maySendEventOfType(EventType.MESSAGE, userId) } /** @@ -98,7 +87,7 @@ data class PowerLevels( * @param eventTypeString the type of event (in Event.EVENT_TYPE_XXX values) * @return the required minimum power level. */ - fun minimumPowerLevelForSendingEventAsMessage(eventTypeString: String?): Int { + fun minimumPowerLevelForSendingEventAsMessage(eventTypeString: String?): Int { return events[eventTypeString] ?: eventsDefault } @@ -109,29 +98,24 @@ data class PowerLevels( * @param eventTypeString the type of event (in Event.EVENT_TYPE_STATE_ values). * @return the required minimum power level. */ - fun minimumPowerLevelForSendingEventAsStateEvent(eventTypeString: String?): Int { + fun minimumPowerLevelForSendingEventAsStateEvent(eventTypeString: String?): Int { return events[eventTypeString] ?: stateDefault } - /** * Get the notification level for a dedicated key. * * @param key the notification key * @return the level */ - fun notificationLevel(key: String?): Int { - if (null != key && notifications.containsKey(key)) { - val valAsVoid = notifications[key] + fun notificationLevel(key: String): Int { + val valAsVoid = notifications[key] ?: return 50 - // the first implementation was a string value - return if (valAsVoid is String) { - Integer.parseInt(valAsVoid) - } else { - valAsVoid as Int - } + // the first implementation was a string value + return if (valAsVoid is String) { + valAsVoid.toInt() + } else { + valAsVoid as Int } - - return 50 } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/ReactionAggregatedSummary.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/ReactionAggregatedSummary.kt index 7036f68186..5ab4804fae 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/ReactionAggregatedSummary.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/ReactionAggregatedSummary.kt @@ -23,4 +23,4 @@ data class ReactionAggregatedSummary( val firstTimestamp: Long, // unix timestamp val sourceEvents: List, val localEchoEvents: List -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/ReadReceipt.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/ReadReceipt.kt index e168dc1e5b..4bb31bccdc 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/ReadReceipt.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/ReadReceipt.kt @@ -21,4 +21,4 @@ import im.vector.matrix.android.api.session.user.model.User data class ReadReceipt( val user: User, val originServerTs: Long -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomAliasesContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomAliasesContent.kt index 74b29b7aea..8a857a1c02 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomAliasesContent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomAliasesContent.kt @@ -25,4 +25,4 @@ import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) data class RoomAliasesContent( @Json(name = "aliases") val aliases: List = emptyList() -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomAvatarContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomAvatarContent.kt index 8f81632bf4..fc0814817c 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomAvatarContent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomAvatarContent.kt @@ -25,4 +25,4 @@ import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) data class RoomAvatarContent( @Json(name = "url") val avatarUrl: String? = null -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomCanonicalAliasContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomCanonicalAliasContent.kt index abaa9f0a6c..a66f23555d 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomCanonicalAliasContent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomCanonicalAliasContent.kt @@ -25,4 +25,4 @@ import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) data class RoomCanonicalAliasContent( @Json(name = "alias") val canonicalAlias: String? = null -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomDirectoryVisibility.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomDirectoryVisibility.kt index 2e1b5a3922..ab3407392c 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomDirectoryVisibility.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomDirectoryVisibility.kt @@ -21,4 +21,4 @@ import com.squareup.moshi.Json enum class RoomDirectoryVisibility { @Json(name = "private") PRIVATE, @Json(name = "public") PUBLIC -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomHistoryVisibility.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomHistoryVisibility.kt index 9260b0112c..a066aaadd5 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomHistoryVisibility.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomHistoryVisibility.kt @@ -23,4 +23,4 @@ enum class RoomHistoryVisibility { @Json(name = "invited") INVITED, @Json(name = "joined") JOINED, @Json(name = "world_readable") WORLD_READABLE -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomHistoryVisibilityContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomHistoryVisibilityContent.kt index 7781bcdaf7..96bd910781 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomHistoryVisibilityContent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomHistoryVisibilityContent.kt @@ -22,4 +22,4 @@ import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) data class RoomHistoryVisibilityContent( @Json(name = "history_visibility") val historyVisibility: RoomHistoryVisibility? = null -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomMember.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomMember.kt index 10c3e8ec7c..aa73727685 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomMember.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomMember.kt @@ -31,4 +31,4 @@ data class RoomMember( @Json(name = "is_direct") val isDirect: Boolean = false, @Json(name = "third_party_invite") val thirdPartyInvite: Invite? = null, @Json(name = "unsigned") val unsignedData: UnsignedData? = null -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomNameContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomNameContent.kt index 48cbb91cac..72bdaf1d36 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomNameContent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomNameContent.kt @@ -25,4 +25,4 @@ import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) data class RoomNameContent( @Json(name = "name") val name: String? = null -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomSummary.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomSummary.kt index 099deae937..447ba563de 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomSummary.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomSummary.kt @@ -38,9 +38,13 @@ data class RoomSummary( val tags: List = emptyList(), val membership: Membership = Membership.NONE, val versioningState: VersioningState = VersioningState.NONE, + val readMarkerId: String? = null, val userDrafts: List = emptyList() ) { val isVersioned: Boolean get() = versioningState != VersioningState.NONE -} \ No newline at end of file + + val hasNewMessages: Boolean + get() = notificationCount != 0 +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomTopicContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomTopicContent.kt index 8a6e3f90f3..2439618f46 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomTopicContent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomTopicContent.kt @@ -25,4 +25,4 @@ import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) data class RoomTopicContent( @Json(name = "topic") val topic: String? = null -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/Signed.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/Signed.kt index 4f0e5212fb..43b957bde3 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/Signed.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/Signed.kt @@ -22,4 +22,4 @@ data class Signed( @Json(name = "token") val token: String, @Json(name = "signatures") val signatures: Any, @Json(name = "mxid") val mxid: String -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/VersioningState.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/VersioningState.kt index f2753fbf35..a878e10e3f 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/VersioningState.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/VersioningState.kt @@ -20,4 +20,4 @@ enum class VersioningState { NONE, UPGRADED_ROOM_NOT_JOINED, UPGRADED_ROOM_JOINED -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/call/CallAnswerContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/call/CallAnswerContent.kt index 0539571884..24eb68bd78 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/call/CallAnswerContent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/call/CallAnswerContent.kt @@ -31,5 +31,4 @@ data class CallAnswerContent( @Json(name = "type") val type: String, @Json(name = "sdp") val sdp: String ) - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/call/CallCandidatesContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/call/CallCandidatesContent.kt index 48c02f3df8..5fb4db84a3 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/call/CallCandidatesContent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/call/CallCandidatesContent.kt @@ -32,5 +32,4 @@ data class CallCandidatesContent( @Json(name = "sdpMLineIndex") val sdpMLineIndex: String, @Json(name = "candidate") val candidate: String ) - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/call/CallInviteContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/call/CallInviteContent.kt index 58e5d561e6..29305d1420 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/call/CallInviteContent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/call/CallInviteContent.kt @@ -37,6 +37,5 @@ data class CallInviteContent( } } - fun isVideo(): Boolean = offer.sdp.contains(Offer.SDP_VIDEO) -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/create/CreateRoomParams.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/create/CreateRoomParams.kt index c707f3c3ef..598aab2d30 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/create/CreateRoomParams.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/create/CreateRoomParams.kt @@ -145,15 +145,7 @@ class CreateRoomParams { */ fun setHistoryVisibility(historyVisibility: RoomHistoryVisibility?) { // Remove the existing value if any. - if (initialStates != null && !initialStates!!.isEmpty()) { - val newInitialStates = ArrayList() - for (event in initialStates!!) { - if (event.getClearType() != EventType.STATE_HISTORY_VISIBILITY) { - newInitialStates.add(event) - } - } - initialStates = newInitialStates - } + initialStates?.removeAll { it.getClearType() == EventType.STATE_HISTORY_VISIBILITY } if (historyVisibility != null) { val contentMap = HashMap() @@ -243,4 +235,4 @@ class CreateRoomParams { // TODO add phonenumbers when it will be available } } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/create/CreateRoomPreset.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/create/CreateRoomPreset.kt index 9548062bae..eafe9ef292 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/create/CreateRoomPreset.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/create/CreateRoomPreset.kt @@ -27,4 +27,4 @@ enum class CreateRoomPreset { @Json(name = "trusted_private_chat") PRESET_TRUSTED_PRIVATE_CHAT -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/create/Invite3Pid.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/create/Invite3Pid.kt index 5ad920a32b..8e3386080f 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/create/Invite3Pid.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/create/Invite3Pid.kt @@ -39,4 +39,4 @@ data class Invite3Pid( * The invitee's third party identifier. */ val address: String -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/create/RoomCreateContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/create/RoomCreateContent.kt index afb318bce9..323c7d7445 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/create/RoomCreateContent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/create/RoomCreateContent.kt @@ -28,5 +28,3 @@ data class RoomCreateContent( @Json(name = "room_version") val roomVersion: String? = null, @Json(name = "predecessor") val predecessor: Predecessor? = null ) - - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/AudioInfo.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/AudioInfo.kt index de30d46024..eef6b283c6 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/AudioInfo.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/AudioInfo.kt @@ -35,4 +35,4 @@ data class AudioInfo( * The duration of the audio in milliseconds. */ @Json(name = "duration") val duration: Int = 0 -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/FileInfo.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/FileInfo.kt index d5dfb04f19..b8ed516d9d 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/FileInfo.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/FileInfo.kt @@ -46,4 +46,4 @@ data class FileInfo( * Information on the encrypted thumbnail file, as specified in End-to-end encryption. Only present if the thumbnail is encrypted. */ @Json(name = "thumbnail_file") val thumbnailFile: EncryptedFileInfo? = null -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/ImageInfo.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/ImageInfo.kt index 729bc604c1..20af927e46 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/ImageInfo.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/ImageInfo.kt @@ -42,16 +42,6 @@ data class ImageInfo( */ @Json(name = "size") val size: Int = 0, - /** - * Not documented - */ - @Json(name = "rotation") val rotation: Int = 0, - - /** - * Not documented - */ - @Json(name = "orientation") val orientation: Int = 0, - /** * Metadata about the image referred to in thumbnail_url. */ @@ -66,4 +56,4 @@ data class ImageInfo( * Information on the encrypted thumbnail file, as specified in End-to-end encryption. Only present if the thumbnail is encrypted. */ @Json(name = "thumbnail_file") val thumbnailFile: EncryptedFileInfo? = null -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/LocationInfo.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/LocationInfo.kt index f00d48826b..ab6e5e66e9 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/LocationInfo.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/LocationInfo.kt @@ -36,4 +36,4 @@ data class LocationInfo( * Information on the encrypted thumbnail file, as specified in End-to-end encryption. Only present if the thumbnail is encrypted. */ @Json(name = "thumbnail_file") val thumbnailFile: EncryptedFileInfo? = null -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageContent.kt index c116c6b315..157ff00d69 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageContent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageContent.kt @@ -19,7 +19,6 @@ package im.vector.matrix.android.api.session.room.model.message import im.vector.matrix.android.api.session.events.model.Content import im.vector.matrix.android.api.session.room.model.relation.RelationDefaultContent - interface MessageContent { val type: String val body: String @@ -27,7 +26,6 @@ interface MessageContent { val newContent: Content? } - fun MessageContent?.isReply(): Boolean { return this?.relatesTo?.inReplyTo?.eventId != null } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageDefaultContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageDefaultContent.kt index 45ce9542e0..705dbf5d85 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageDefaultContent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageDefaultContent.kt @@ -27,4 +27,4 @@ data class MessageDefaultContent( @Json(name = "body") override val body: String, @Json(name = "m.relates_to") override val relatesTo: RelationDefaultContent? = null, @Json(name = "m.new_content") override val newContent: Content? = null -) : MessageContent \ No newline at end of file +) : MessageContent diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageEmoteContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageEmoteContent.kt index 88fd3bc1cd..ec340659a2 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageEmoteContent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageEmoteContent.kt @@ -29,4 +29,4 @@ data class MessageEmoteContent( @Json(name = "formatted_body") val formattedBody: String? = null, @Json(name = "m.relates_to") override val relatesTo: RelationDefaultContent? = null, @Json(name = "m.new_content") override val newContent: Content? = null -) : MessageContent \ No newline at end of file +) : MessageContent diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageEncryptedContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageEncryptedContent.kt index 125c18bb00..110b9c68f0 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageEncryptedContent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageEncryptedContent.kt @@ -18,7 +18,6 @@ package im.vector.matrix.android.api.session.room.model.message import im.vector.matrix.android.internal.crypto.model.rest.EncryptedFileInfo - /** * Interface for message which can contains an encrypted file */ diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageLocationContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageLocationContent.kt index deddec12a5..15c746fd38 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageLocationContent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageLocationContent.kt @@ -45,4 +45,4 @@ data class MessageLocationContent( @Json(name = "m.relates_to") override val relatesTo: RelationDefaultContent? = null, @Json(name = "m.new_content") override val newContent: Content? = null -) : MessageContent \ No newline at end of file +) : MessageContent diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageNoticeContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageNoticeContent.kt index 54037c600f..9a4fea1060 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageNoticeContent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageNoticeContent.kt @@ -29,4 +29,4 @@ data class MessageNoticeContent( @Json(name = "formatted_body") val formattedBody: String? = null, @Json(name = "m.relates_to") override val relatesTo: RelationDefaultContent? = null, @Json(name = "m.new_content") override val newContent: Content? = null -) : MessageContent \ No newline at end of file +) : MessageContent diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageTextContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageTextContent.kt index 3256d8306f..001b9ff0dd 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageTextContent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageTextContent.kt @@ -29,4 +29,4 @@ data class MessageTextContent( @Json(name = "formatted_body") val formattedBody: String? = null, @Json(name = "m.relates_to") override val relatesTo: RelationDefaultContent? = null, @Json(name = "m.new_content") override val newContent: Content? = null -) : MessageContent \ No newline at end of file +) : MessageContent diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageType.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageType.kt index 7db3301898..8cef40f21a 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageType.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageType.kt @@ -30,4 +30,4 @@ object MessageType { // Add, in local, a fake message type in order to StickerMessage can inherit Message class // Because sticker isn't a message type but a event type without msgtype field const val MSGTYPE_STICKER_LOCAL = "org.matrix.android.sdk.sticker" -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/ThumbnailInfo.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/ThumbnailInfo.kt index 1e308d79fa..0ef1b8f658 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/ThumbnailInfo.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/ThumbnailInfo.kt @@ -40,4 +40,4 @@ data class ThumbnailInfo( * The mimetype of the image, e.g. "image/jpeg". */ @Json(name = "mimetype") val mimeType: String -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/VideoInfo.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/VideoInfo.kt index 0622037896..a7d4708d33 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/VideoInfo.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/VideoInfo.kt @@ -61,4 +61,4 @@ data class VideoInfo( * Information on the encrypted thumbnail file, as specified in End-to-end encryption. Only present if the thumbnail is encrypted. */ @Json(name = "thumbnail_file") val thumbnailFile: EncryptedFileInfo? = null -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/relation/ReactionInfo.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/relation/ReactionInfo.kt index 72a30ec2e2..c4cbde98eb 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/relation/ReactionInfo.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/relation/ReactionInfo.kt @@ -24,6 +24,6 @@ data class ReactionInfo( @Json(name = "rel_type") override val type: String?, @Json(name = "event_id") override val eventId: String, val key: String, - //always null for reaction + // always null for reaction @Json(name = "m.in_reply_to") override val inReplyTo: ReplyToContent? = null -) : RelationContent \ No newline at end of file +) : RelationContent diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/relation/RelationContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/relation/RelationContent.kt index 5f89a482d0..c66d1b9770 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/relation/RelationContent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/relation/RelationContent.kt @@ -23,4 +23,4 @@ interface RelationContent { val type: String? val eventId: String? val inReplyTo: ReplyToContent? -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/relation/RelationService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/relation/RelationService.kt index 0c4e1bebc1..5af5183dfa 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/relation/RelationService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/relation/RelationService.kt @@ -21,6 +21,7 @@ import im.vector.matrix.android.api.session.events.model.Event import im.vector.matrix.android.api.session.room.model.EventAnnotationsSummary import im.vector.matrix.android.api.session.room.timeline.TimelineEvent import im.vector.matrix.android.api.util.Cancelable +import im.vector.matrix.android.api.util.Optional /** * In some cases, events may wish to reference other events. @@ -47,26 +48,21 @@ import im.vector.matrix.android.api.util.Cancelable */ interface RelationService { - /** * Sends a reaction (emoji) to the targetedEvent. - * @param reaction the reaction (preferably emoji) * @param targetEventId the id of the event being reacted + * @param reaction the reaction (preferably emoji) */ - fun sendReaction(reaction: String, - targetEventId: String): Cancelable - + fun sendReaction(targetEventId: String, + reaction: String): Cancelable /** * Undo a reaction (emoji) to the targetedEvent. - * @param reaction the reaction (preferably emoji) * @param targetEventId the id of the event being reacted - * @param myUserId used to know if a reaction event was made by the user + * @param reaction the reaction (preferably emoji) */ - fun undoReaction(reaction: String, - targetEventId: String, - myUserId: String)//: Cancelable - + fun undoReaction(targetEventId: String, + reaction: String): Cancelable /** * Edit a text message body. Limited to "m.text" contentType @@ -80,7 +76,6 @@ interface RelationService { newBodyAutoMarkdown: Boolean, compatibilityBodyText: String = "* $newBodyText"): Cancelable - /** * Edit a reply. This is a special case because replies contains fallback text as a prefix. * This method will take the new body (stripped from fallbacks) and re-add them before sending. @@ -95,11 +90,10 @@ interface RelationService { compatibilityBodyText: String = "* $newBodyText"): Cancelable /** - * Get's the edit history of the given event + * Get the edit history of the given event */ fun fetchEditHistory(eventId: String, callback: MatrixCallback>) - /** * Reply to an event in the timeline (must be in same room) * https://matrix.org/docs/spec/client_server/r0.4.0.html#id350 @@ -111,7 +105,5 @@ interface RelationService { replyText: String, autoMarkdown: Boolean = false): Cancelable? - fun getEventSummaryLive(eventId: String): LiveData - - -} \ No newline at end of file + fun getEventSummaryLive(eventId: String): LiveData> +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/tag/RoomTag.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/tag/RoomTag.kt index 0623e8d93c..9e85ba3255 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/tag/RoomTag.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/tag/RoomTag.kt @@ -27,5 +27,4 @@ data class RoomTag( val ROOM_TAG_NO_TAG = "m.recent" val ROOM_TAG_SERVER_NOTICE = "m.server_notice" } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/thirdparty/RoomDirectoryData.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/thirdparty/RoomDirectoryData.kt index 11a347c0ee..e651500af1 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/thirdparty/RoomDirectoryData.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/thirdparty/RoomDirectoryData.kt @@ -51,5 +51,4 @@ data class RoomDirectoryData( companion object { const val DEFAULT_HOME_SERVER_NAME = "Matrix" } - } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/thirdparty/ThirdPartyProtocol.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/thirdparty/ThirdPartyProtocol.kt index a31df79436..b066cff164 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/thirdparty/ThirdPartyProtocol.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/thirdparty/ThirdPartyProtocol.kt @@ -59,4 +59,4 @@ data class ThirdPartyProtocol( */ @Json(name = "instances") var instances: List? = null -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/thirdparty/ThirdPartyProtocolInstance.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/thirdparty/ThirdPartyProtocolInstance.kt index d2bea70051..50f92356fb 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/thirdparty/ThirdPartyProtocolInstance.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/thirdparty/ThirdPartyProtocolInstance.kt @@ -51,10 +51,9 @@ data class ThirdPartyProtocolInstance( @Json(name = "instance_id") var instanceId: String? = null, - /** * FIXDOC Not documented on matrix.org doc */ @Json(name = "bot_user_id") var botUserId: String? = null -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/read/ReadService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/read/ReadService.kt index d97fc497f0..c9bb6fbf9b 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/read/ReadService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/read/ReadService.kt @@ -19,6 +19,7 @@ package im.vector.matrix.android.api.session.room.read import androidx.lifecycle.LiveData import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.session.room.model.ReadReceipt +import im.vector.matrix.android.api.util.Optional /** * This interface defines methods to handle read receipts and read marker in a room. It's implemented at the room level. @@ -40,7 +41,24 @@ interface ReadService { */ fun setReadMarker(fullyReadEventId: String, callback: MatrixCallback) + /** + * Check if an event is already read, ie. your read receipt is set on a more recent event. + */ fun isEventRead(eventId: String): Boolean + /** + * Returns a live read marker id for the room. + */ + fun getReadMarkerLive(): LiveData> + + /** + * Returns a live read receipt id for the room. + */ + fun getMyReadReceiptLive(): LiveData> + + /** + * Returns a live list of read receipts for a given event + * @param eventId: the event + */ fun getEventReadReceiptsLive(eventId: String): LiveData> -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/reporting/ReportingService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/reporting/ReportingService.kt new file mode 100644 index 0000000000..71ce02ac69 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/reporting/ReportingService.kt @@ -0,0 +1,32 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.matrix.android.api.session.room.reporting + +import im.vector.matrix.android.api.MatrixCallback +import im.vector.matrix.android.api.util.Cancelable + +/** + * This interface defines methods to report content of an event. + */ +interface ReportingService { + + /** + * Report content + * Ref: https://matrix.org/docs/spec/client_server/latest#post-matrix-client-r0-rooms-roomid-report-eventid + */ + fun reportContent(eventId: String, score: Int, reason: String, callback: MatrixCallback): Cancelable +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/send/DraftService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/send/DraftService.kt index c700b40a08..2324f1e221 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/send/DraftService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/send/DraftService.kt @@ -35,5 +35,4 @@ interface DraftService { * The draft list can contain one draft for {regular, reply, quote} and an arbitrary number of {edit} drafts */ fun getDraftsLive(): LiveData> - } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/send/SendService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/send/SendService.kt index ae276adb73..8c783837a2 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/send/SendService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/send/SendService.kt @@ -22,7 +22,6 @@ import im.vector.matrix.android.api.session.room.model.message.MessageType import im.vector.matrix.android.api.session.room.timeline.TimelineEvent import im.vector.matrix.android.api.util.Cancelable - /** * This interface defines methods to send events in a room. It's implemented at the room level. */ @@ -66,7 +65,6 @@ interface SendService { */ fun redactEvent(event: Event, reason: String?): Cancelable - /** * Schedule this message to be resent * @param localEcho the unsent local echo @@ -79,7 +77,6 @@ interface SendService { */ fun resendMediaMessage(localEcho: TimelineEvent): Cancelable? - /** * Remove this failed message from the timeline * @param localEcho the unsent local echo @@ -92,5 +89,4 @@ interface SendService { * Resend all failed messages one by one (and keep order) */ fun resendAllFailedMessages() - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/send/SendState.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/send/SendState.kt index aaa7020be6..cfe3c9ae1a 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/send/SendState.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/send/SendState.kt @@ -16,7 +16,6 @@ package im.vector.matrix.android.api.session.room.send - enum class SendState { UNKNOWN, // the event has not been sent @@ -46,7 +45,4 @@ enum class SendState { fun hasFailed() = HAS_FAILED_STATES.contains(this) fun isSending() = IS_SENDING_STATES.contains(this) - } - - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/state/StateService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/state/StateService.kt index 21aae95bdf..06f4a9c7ee 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/state/StateService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/state/StateService.kt @@ -27,5 +27,4 @@ interface StateService { fun updateTopic(topic: String, callback: MatrixCallback) fun getStateEvent(eventType: String): Event? - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/timeline/Timeline.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/timeline/Timeline.kt index 314c9f61b8..c03effd7ad 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/timeline/Timeline.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/timeline/Timeline.kt @@ -32,6 +32,8 @@ interface Timeline { var listener: Listener? + val isLive: Boolean + /** * This should be called before any other method after creating the timeline. It ensures the underlying database is open */ @@ -42,6 +44,12 @@ interface Timeline { */ fun dispose() + /** + * This method restarts the timeline, erases all built events and pagination states. + * It then loads events around the eventId. If eventId is null, it does restart the live timeline. + */ + fun restartWithEventId(eventId: String?) + /** * Check if the timeline can be enriched by paginating. * @param the direction to check in @@ -56,9 +64,36 @@ interface Timeline { */ fun paginate(direction: Direction, count: Int) - fun pendingEventCount() : Int + /** + * Returns the number of sending events + */ + fun pendingEventCount(): Int - fun failedToDeliverEventCount() : Int + /** + * Returns the number of failed sending events. + */ + fun failedToDeliverEventCount(): Int + + /** + * Returns the index of a built event or null. + */ + fun getIndexOfEvent(eventId: String?): Int? + + /** + * Returns the built [TimelineEvent] at index or null + */ + fun getTimelineEventAtIndex(index: Int): TimelineEvent? + + /** + * Returns the built [TimelineEvent] with eventId or null + */ + fun getTimelineEventWithId(eventId: String?): TimelineEvent? + + /** + * Returns the first displayable events starting from eventId. + * It does depend on the provided [TimelineSettings]. + */ + fun getFirstDisplayableEventId(eventId: String): String? interface Listener { /** @@ -81,5 +116,4 @@ interface Timeline { */ BACKWARDS } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/timeline/TimelineEvent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/timeline/TimelineEvent.kt index 73ef7b779a..43c1544ffd 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/timeline/TimelineEvent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/timeline/TimelineEvent.kt @@ -40,7 +40,8 @@ data class TimelineEvent( val isUniqueDisplayName: Boolean, val senderAvatar: String?, val annotations: EventAnnotationsSummary? = null, - val readReceipts: List = emptyList() + val readReceipts: List = emptyList(), + val hasReadMarker: Boolean = false ) { val metadata = HashMap() @@ -87,7 +88,6 @@ data class TimelineEvent( } } - /** * Tells if the event has been edited */ @@ -106,7 +106,6 @@ fun TimelineEvent.getEditedEventId(): String? { fun TimelineEvent.getLastMessageContent(): MessageContent? = annotations?.editSummary?.aggregatedContent?.toModel() ?: root.getClearContent().toModel() - /** * Get last Message body, after a possible edition */ @@ -120,7 +119,6 @@ fun TimelineEvent.getLastMessageBody(): String? { return null } - fun TimelineEvent.getTextEditableContent(): String? { val originalContent = root.getClearContent().toModel() ?: return null val isReply = originalContent.isReply() || root.content.toModel()?.relatesTo?.inReplyTo?.eventId != null diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/timeline/TimelineService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/timeline/TimelineService.kt index fdf99bd22c..2b23ee40ca 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/timeline/TimelineService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/timeline/TimelineService.kt @@ -17,6 +17,7 @@ package im.vector.matrix.android.api.session.room.timeline import androidx.lifecycle.LiveData +import im.vector.matrix.android.api.util.Optional /** * This interface defines methods to interact with the timeline. It's implemented at the room level. @@ -32,9 +33,7 @@ interface TimelineService { */ fun createTimeline(eventId: String?, settings: TimelineSettings): Timeline - fun getTimeLineEvent(eventId: String): TimelineEvent? - - fun liveTimeLineEvent(eventId: String): LiveData -} \ No newline at end of file + fun getTimeLineEventLive(eventId: String): LiveData> +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/securestorage/SecureStorageService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/securestorage/SecureStorageService.kt index d56b6150ee..bae8132990 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/securestorage/SecureStorageService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/securestorage/SecureStorageService.kt @@ -24,5 +24,4 @@ interface SecureStorageService { fun securelyStoreObject(any: Any, keyAlias: String, outputStream: OutputStream) fun loadSecureSecret(inputStream: InputStream, keyAlias: String): T? - } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/signout/SignOutService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/signout/SignOutService.kt index 11f7cd57f7..5a0638fb6e 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/signout/SignOutService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/signout/SignOutService.kt @@ -27,5 +27,4 @@ interface SignOutService { * Sign out */ fun signOut(callback: MatrixCallback) - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/sync/FilterService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/sync/FilterService.kt index 4a29013def..e995e775a9 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/sync/FilterService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/sync/FilterService.kt @@ -30,4 +30,4 @@ interface FilterService { * Configure the filter for the sync */ fun setFilter(filterPreset: FilterPreset) -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/sync/SyncState.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/sync/SyncState.kt index 8c34e392b5..4db40b2c55 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/sync/SyncState.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/sync/SyncState.kt @@ -23,4 +23,4 @@ sealed class SyncState { object KILLING : SyncState() object KILLED : SyncState() object NO_NETWORK : SyncState() -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/user/UserService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/user/UserService.kt index d3c58edd94..d3de777e34 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/user/UserService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/user/UserService.kt @@ -21,6 +21,7 @@ import androidx.paging.PagedList import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.session.user.model.User import im.vector.matrix.android.api.util.Cancelable +import im.vector.matrix.android.api.util.Optional /** * This interface defines methods to get users. It's implemented at the session level. @@ -47,9 +48,9 @@ interface UserService { /** * Observe a live user from a userId * @param userId the userId to look for. - * @return a Livedata of user with userId + * @return a LiveData of user with userId */ - fun liveUser(userId: String): LiveData + fun liveUser(userId: String): LiveData> /** * Observe a live list of users sorted alphabetically @@ -63,5 +64,4 @@ interface UserService { * @return a Livedata of users */ fun livePagedUsers(filter: String? = null): LiveData> - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/user/model/User.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/user/model/User.kt index 50e76053bc..f569f5e47e 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/user/model/User.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/user/model/User.kt @@ -24,4 +24,4 @@ data class User( val userId: String, val displayName: String? = null, val avatarUrl: String? = null -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/util/Cancelable.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/util/Cancelable.kt index d2573de455..7f3543dec2 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/util/Cancelable.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/util/Cancelable.kt @@ -26,7 +26,6 @@ interface Cancelable { * The cancel method, it does nothing by default. */ fun cancel() { - //no-op + // no-op } } - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/util/ContentUtils.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/util/ContentUtils.kt index ad17d26b20..9131cf143b 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/util/ContentUtils.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/util/ContentUtils.kt @@ -15,7 +15,6 @@ */ package im.vector.matrix.android.api.util - object ContentUtils { fun extractUsefulTextFromReply(repliedBody: String): String { val lines = repliedBody.lines() @@ -39,9 +38,10 @@ object ContentUtils { fun extractUsefulTextFromHtmlReply(repliedBody: String): String { if (repliedBody.startsWith("")) { val closingTagIndex = repliedBody.lastIndexOf("") - if (closingTagIndex != -1) + if (closingTagIndex != -1) { return repliedBody.substring(closingTagIndex + "".length).trim() + } } return repliedBody } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/util/MatrixCallbackDelegate.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/util/MatrixCallbackDelegate.kt index 2b4e30a1e6..06b157daeb 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/util/MatrixCallbackDelegate.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/util/MatrixCallbackDelegate.kt @@ -21,4 +21,4 @@ import im.vector.matrix.android.api.MatrixCallback /** * Simple MatrixCallback implementation which delegate its calls to another callback */ -open class MatrixCallbackDelegate(private val callback: MatrixCallback) : MatrixCallback by callback \ No newline at end of file +open class MatrixCallbackDelegate(private val callback: MatrixCallback) : MatrixCallback by callback diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/util/Optional.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/util/Optional.kt new file mode 100644 index 0000000000..2f602d0b84 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/util/Optional.kt @@ -0,0 +1,45 @@ +/* + + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + + */ +package im.vector.matrix.android.api.util + +data class Optional constructor(private val value: T?) { + + fun get(): T { + return value!! + } + + fun getOrNull(): T? { + return value + } + + fun getOrElse(fn: () -> T): T { + return value ?: fn() + } + + fun hasValue(): Boolean { + return value != null + } + + companion object { + fun from(value: T?): Optional { + return Optional(value) + } + } +} + +fun T?.toOptional() = Optional(this) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/util/Types.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/util/Types.kt index c2f710df1f..bfb9a59956 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/util/Types.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/util/Types.kt @@ -21,4 +21,4 @@ import java.lang.reflect.ParameterizedType typealias JsonDict = Map -internal val JSON_DICT_PARAMETERIZED_TYPE: ParameterizedType = Types.newParameterizedType(Map::class.java, String::class.java, Any::class.java) \ No newline at end of file +internal val JSON_DICT_PARAMETERIZED_TYPE: ParameterizedType = Types.newParameterizedType(Map::class.java, String::class.java, Any::class.java) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/SessionManager.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/SessionManager.kt index 21f16d3d03..c813a6813f 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/SessionManager.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/SessionManager.kt @@ -56,4 +56,4 @@ internal class SessionManager @Inject constructor(private val matrixComponent: M .create(matrixComponent, sessionParams) } } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/AuthAPI.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/AuthAPI.kt index d42962c53e..bfc2b76db7 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/AuthAPI.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/AuthAPI.kt @@ -47,5 +47,4 @@ internal interface AuthAPI { @Headers("CONNECT_TIMEOUT:60000", "READ_TIMEOUT:60000", "WRITE_TIMEOUT:60000") @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "login") fun login(@Body loginParams: PasswordLoginParams): Call - } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/AuthModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/AuthModule.kt index 399605469d..31a85afbfb 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/AuthModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/AuthModule.kt @@ -55,11 +55,9 @@ internal abstract class AuthModule { } } - @Binds abstract fun bindSessionParamsStore(sessionParamsStore: RealmSessionParamsStore): SessionParamsStore @Binds abstract fun bindAuthenticator(authenticator: DefaultAuthenticator): Authenticator - } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/DefaultAuthenticator.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/DefaultAuthenticator.kt index 949aa6611e..e379090677 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/DefaultAuthenticator.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/DefaultAuthenticator.kt @@ -39,9 +39,10 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import okhttp3.OkHttpClient import javax.inject.Inject +import javax.inject.Provider internal class DefaultAuthenticator @Inject constructor(@Unauthenticated - private val okHttpClient: OkHttpClient, + private val okHttpClient: Provider, private val retrofitFactory: RetrofitFactory, private val coroutineDispatchers: MatrixCoroutineDispatchers, private val sessionParamsStore: SessionParamsStore, @@ -97,7 +98,6 @@ internal class DefaultAuthenticator @Inject constructor(@Unauthenticated private suspend fun authenticate(homeServerConnectionConfig: HomeServerConnectionConfig, login: String, password: String) = withContext(coroutineDispatchers.io) { - val authAPI = buildAuthAPI(homeServerConnectionConfig) val loginParams = if (Patterns.EMAIL_ADDRESS.matcher(login).matches()) { PasswordLoginParams.thirdPartyIdentifier(ThreePidMedium.EMAIL, login, password, "Mobile") @@ -119,9 +119,7 @@ internal class DefaultAuthenticator @Inject constructor(@Unauthenticated } private fun buildAuthAPI(homeServerConnectionConfig: HomeServerConnectionConfig): AuthAPI { - val retrofit = retrofitFactory.create(okHttpClient, homeServerConnectionConfig.homeServerUri.toString()) + val retrofit = retrofitFactory.create(okHttpClient.get(), homeServerConnectionConfig.homeServerUri.toString()) return retrofit.create(AuthAPI::class.java) } - - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/SessionParamsStore.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/SessionParamsStore.kt index 9067e8188c..e1fef7e2eb 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/SessionParamsStore.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/SessionParamsStore.kt @@ -32,4 +32,4 @@ internal interface SessionParamsStore { fun delete(userId: String): Try fun deleteAll(): Try -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/data/InteractiveAuthenticationFlow.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/data/InteractiveAuthenticationFlow.kt index e1f963ff3d..a6c027900f 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/data/InteractiveAuthenticationFlow.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/data/InteractiveAuthenticationFlow.kt @@ -38,4 +38,4 @@ data class InteractiveAuthenticationFlow( const val TYPE_LOGIN_TOKEN = "m.login.token" const val TYPE_LOGIN_PASSWORD = "m.login.password" } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/data/LoginFlowResponse.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/data/LoginFlowResponse.kt index 78fd372beb..598506d0a7 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/data/LoginFlowResponse.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/data/LoginFlowResponse.kt @@ -23,4 +23,4 @@ import com.squareup.moshi.JsonClass data class LoginFlowResponse( @Json(name = "flows") val flows: List -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/data/LoginFlowTypes.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/data/LoginFlowTypes.kt index 1e129f1b45..81196c7414 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/data/LoginFlowTypes.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/data/LoginFlowTypes.kt @@ -25,4 +25,4 @@ object LoginFlowTypes { const val MSISDN = "m.login.msisdn" const val RECAPTCHA = "m.login.recaptcha" const val DUMMY = "m.login.dummy" -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/data/LoginParams.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/data/LoginParams.kt index af859aeba4..e37977425a 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/data/LoginParams.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/data/LoginParams.kt @@ -18,4 +18,4 @@ package im.vector.matrix.android.internal.auth.data internal interface LoginParams { val type: String -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/data/PasswordLoginParams.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/data/PasswordLoginParams.kt index 372b18a931..39b1dd8760 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/data/PasswordLoginParams.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/data/PasswordLoginParams.kt @@ -26,7 +26,6 @@ internal data class PasswordLoginParams(@Json(name = "identifier") val identifie @Json(name = "initial_device_display_name") val deviceDisplayName: String?, @Json(name = "device_id") val deviceId: String?) : LoginParams { - companion object { val IDENTIFIER_KEY_TYPE_USER = "m.id.user" @@ -40,7 +39,6 @@ internal data class PasswordLoginParams(@Json(name = "identifier") val identifie val IDENTIFIER_KEY_COUNTRY = "country" val IDENTIFIER_KEY_NUMBER = "number" - fun userIdentifier(user: String, password: String, deviceDisplayName: String? = null, @@ -49,7 +47,6 @@ internal data class PasswordLoginParams(@Json(name = "identifier") val identifie identifier[IDENTIFIER_KEY_TYPE] = IDENTIFIER_KEY_TYPE_USER identifier[IDENTIFIER_KEY_USER] = user return PasswordLoginParams(identifier, password, LoginFlowTypes.PASSWORD, deviceDisplayName, deviceId) - } fun thirdPartyIdentifier(medium: String, @@ -62,7 +59,6 @@ internal data class PasswordLoginParams(@Json(name = "identifier") val identifie identifier[IDENTIFIER_KEY_MEDIUM] = medium identifier[IDENTIFIER_KEY_ADDRESS] = address return PasswordLoginParams(identifier, password, LoginFlowTypes.PASSWORD, deviceDisplayName, deviceId) - } } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/data/ThreePidMedium.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/data/ThreePidMedium.kt index bf16544972..b1aeb9370b 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/data/ThreePidMedium.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/data/ThreePidMedium.kt @@ -19,4 +19,4 @@ package im.vector.matrix.android.internal.auth.data internal object ThreePidMedium { const val EMAIL = "email" const val MSISDN = "msisdn" -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/db/RealmSessionParamsStore.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/db/RealmSessionParamsStore.kt index 38771c91b3..7ec5d24559 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/db/RealmSessionParamsStore.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/db/RealmSessionParamsStore.kt @@ -99,5 +99,4 @@ internal class RealmSessionParamsStore @Inject constructor(private val mapper: S realm.close() } } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/db/SessionParamsEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/db/SessionParamsEntity.kt index e6569d28ea..d0cc41d1ac 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/db/SessionParamsEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/db/SessionParamsEntity.kt @@ -23,4 +23,4 @@ internal open class SessionParamsEntity( @PrimaryKey var userId: String = "", var credentialsJson: String = "", var homeServerConnectionConfigJson: String = "" -) : RealmObject() \ No newline at end of file +) : RealmObject() diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/db/SessionParamsMapper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/db/SessionParamsMapper.kt index 36a03ab19a..8e64e86582 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/db/SessionParamsMapper.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/db/SessionParamsMapper.kt @@ -50,6 +50,4 @@ internal class SessionParamsMapper @Inject constructor(moshi: Moshi) { } return SessionParamsEntity(sessionParams.credentials.userId, credentialsJson, homeServerConnectionConfigJson) } - - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/registration/RegistrationFlowResponse.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/registration/RegistrationFlowResponse.kt index 0eb7b05bf8..218251cfe5 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/registration/RegistrationFlowResponse.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/registration/RegistrationFlowResponse.kt @@ -50,4 +50,4 @@ data class RegistrationFlowResponse( */ @Json(name = "params") var params: JsonDict? = null -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/CryptoModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/CryptoModule.kt index 742e3ff21a..5a7e28b70f 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/CryptoModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/CryptoModule.kt @@ -74,7 +74,6 @@ internal abstract class CryptoModule { return RealmClearCacheTask(realmConfiguration) } - @JvmStatic @Provides fun providesCryptoStore(@CryptoDatabase @@ -104,7 +103,6 @@ internal abstract class CryptoModule { fun providesCryptoConfig(): MXCryptoConfig { return MXCryptoConfig() } - } @Binds @@ -117,13 +115,13 @@ internal abstract class CryptoModule { abstract fun bindGetDevicesTask(getDevicesTask: DefaultGetDevicesTask): GetDevicesTask @Binds - abstract fun bindSetDeviceNameTask(getDevicesTask: DefaultSetDeviceNameTask): SetDeviceNameTask + abstract fun bindSetDeviceNameTask(setDeviceNameTask: DefaultSetDeviceNameTask): SetDeviceNameTask @Binds - abstract fun bindUploadKeysTask(getDevicesTask: DefaultUploadKeysTask): UploadKeysTask + abstract fun bindUploadKeysTask(uploadKeysTask: DefaultUploadKeysTask): UploadKeysTask @Binds - abstract fun bindDownloadKeysForUsersTask(downloadKeysForUsers: DefaultDownloadKeysForUsers): DownloadKeysForUsersTask + abstract fun bindDownloadKeysForUsersTask(downloadKeysForUsersTask: DefaultDownloadKeysForUsers): DownloadKeysForUsersTask @Binds abstract fun bindCreateKeysBackupVersionTask(createKeysBackupVersionTask: DefaultCreateKeysBackupVersionTask): CreateKeysBackupVersionTask @@ -135,10 +133,10 @@ internal abstract class CryptoModule { abstract fun bindDeleteRoomSessionDataTask(deleteRoomSessionDataTask: DefaultDeleteRoomSessionDataTask): DeleteRoomSessionDataTask @Binds - abstract fun bindDeleteRoomSessionsDataTask(deleteRoomSessionDataTask: DefaultDeleteRoomSessionsDataTask): DeleteRoomSessionsDataTask + abstract fun bindDeleteRoomSessionsDataTask(deleteRoomSessionsDataTask: DefaultDeleteRoomSessionsDataTask): DeleteRoomSessionsDataTask @Binds - abstract fun bindDeleteSessionsDataTask(deleteRoomSessionDataTask: DefaultDeleteSessionsDataTask): DeleteSessionsDataTask + abstract fun bindDeleteSessionsDataTask(deleteSessionsDataTask: DefaultDeleteSessionsDataTask): DeleteSessionsDataTask @Binds abstract fun bindGetKeysBackupLastVersionTask(getKeysBackupLastVersionTask: DefaultGetKeysBackupLastVersionTask): GetKeysBackupLastVersionTask @@ -150,19 +148,19 @@ internal abstract class CryptoModule { abstract fun bindGetRoomSessionDataTask(getRoomSessionDataTask: DefaultGetRoomSessionDataTask): GetRoomSessionDataTask @Binds - abstract fun bindGetRoomSessionsDataTask(getRoomSessionDataTask: DefaultGetRoomSessionsDataTask): GetRoomSessionsDataTask + abstract fun bindGetRoomSessionsDataTask(getRoomSessionsDataTask: DefaultGetRoomSessionsDataTask): GetRoomSessionsDataTask @Binds - abstract fun bindGetSessionsDataTask(getRoomSessionDataTask: DefaultGetSessionsDataTask): GetSessionsDataTask + abstract fun bindGetSessionsDataTask(getSessionsDataTask: DefaultGetSessionsDataTask): GetSessionsDataTask @Binds abstract fun bindStoreRoomSessionDataTask(storeRoomSessionDataTask: DefaultStoreRoomSessionDataTask): StoreRoomSessionDataTask @Binds - abstract fun bindStoreRoomSessionsDataTask(storeRoomSessionDataTask: DefaultStoreRoomSessionsDataTask): StoreRoomSessionsDataTask + abstract fun bindStoreRoomSessionsDataTask(storeRoomSessionsDataTask: DefaultStoreRoomSessionsDataTask): StoreRoomSessionsDataTask @Binds - abstract fun bindStoreSessionsDataTask(storeRoomSessionDataTask: DefaultStoreSessionsDataTask): StoreSessionsDataTask + abstract fun bindStoreSessionsDataTask(storeSessionsDataTask: DefaultStoreSessionsDataTask): StoreSessionsDataTask @Binds abstract fun bindUpdateKeysBackupVersionTask(updateKeysBackupVersionTask: DefaultUpdateKeysBackupVersionTask): UpdateKeysBackupVersionTask diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/DefaultCryptoService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/DefaultCryptoService.kt index 1a94bebde4..cf5506a443 100755 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/DefaultCryptoService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/DefaultCryptoService.kt @@ -21,7 +21,6 @@ package im.vector.matrix.android.internal.crypto import android.content.Context import android.os.Handler import android.os.Looper -import arrow.core.Try import com.squareup.moshi.Types import com.zhuinden.monarchy.Monarchy import dagger.Lazy @@ -31,9 +30,7 @@ import im.vector.matrix.android.api.failure.Failure import im.vector.matrix.android.api.listeners.ProgressListener import im.vector.matrix.android.api.session.crypto.CryptoService import im.vector.matrix.android.api.session.crypto.MXCryptoError -import im.vector.matrix.android.api.session.crypto.keysbackup.KeysBackupService import im.vector.matrix.android.api.session.crypto.keyshare.RoomKeysRequestListener -import im.vector.matrix.android.api.session.crypto.sas.SasVerificationService import im.vector.matrix.android.api.session.events.model.Content import im.vector.matrix.android.api.session.events.model.Event import im.vector.matrix.android.api.session.events.model.EventType @@ -289,24 +286,18 @@ internal class DefaultCryptoService @Inject constructor( outgoingRoomKeyRequestManager.stop() } - override fun isCryptoEnabled(): Boolean { - // TODO Check that this test is correct - return olmDevice != null - } + // Aways enabled on RiotX + override fun isCryptoEnabled() = true /** * @return the Keys backup Service */ - override fun getKeysBackupService(): KeysBackupService { - return keysBackup - } + override fun getKeysBackupService() = keysBackup /** * @return the SasVerificationService */ - override fun getSasVerificationService(): SasVerificationService { - return sasVerificationService - } + override fun getSasVerificationService() = sasVerificationService /** * A sync response has been received @@ -367,29 +358,16 @@ internal class DefaultCryptoService @Inject constructor( */ override fun setDevicesKnown(devices: List, callback: MatrixCallback?) { // build a devices map - val devicesIdListByUserId = HashMap>() + val devicesIdListByUserId = devices.groupBy({ it.userId }, { it.deviceId }) - for (di in devices) { - var deviceIdsList: MutableList? = devicesIdListByUserId[di.userId]?.toMutableList() - - if (null == deviceIdsList) { - deviceIdsList = ArrayList() - devicesIdListByUserId[di.userId] = deviceIdsList - } - deviceIdsList.add(di.deviceId) - } - - val userIds = devicesIdListByUserId.keys - - for (userId in userIds) { + for ((userId, deviceIds) in devicesIdListByUserId) { val storedDeviceIDs = cryptoStore.getUserDevices(userId) // sanity checks if (null != storedDeviceIDs) { var isUpdated = false - val deviceIds = devicesIdListByUserId[userId] - deviceIds?.forEach { deviceId -> + deviceIds.forEach { deviceId -> val device = storedDeviceIDs[deviceId] // assume if the device is either verified or blocked @@ -406,7 +384,6 @@ internal class DefaultCryptoService @Inject constructor( } } - callback?.onSuccess(Unit) } @@ -446,7 +423,7 @@ internal class DefaultCryptoService @Inject constructor( val encryptingClass = MXCryptoAlgorithms.hasEncryptorClassForAlgorithm(algorithm) if (!encryptingClass) { - Timber.e("## setEncryptionInRoom() : Unable to encrypt room ${roomId} with $algorithm") + Timber.e("## setEncryptionInRoom() : Unable to encrypt room $roomId with $algorithm") return false } @@ -558,16 +535,10 @@ internal class DefaultCryptoService @Inject constructor( val t0 = System.currentTimeMillis() Timber.v("## encryptEventContent() starts") runCatching { - safeAlgorithm.encryptEventContent(eventContent, eventType, userIds) - } - .fold( - { - Timber.v("## encryptEventContent() : succeeds after ${System.currentTimeMillis() - t0} ms") - callback.onSuccess(MXEncryptEventContentResult(it, EventType.ENCRYPTED)) - }, - { callback.onFailure(it) } - - ) + val content = safeAlgorithm.encryptEventContent(eventContent, eventType, userIds) + Timber.v("## encryptEventContent() : succeeds after ${System.currentTimeMillis() - t0} ms") + MXEncryptEventContentResult(content, EventType.ENCRYPTED) + }.foldToCallback(callback) } else { val algorithm = getEncryptionAlgorithm(roomId) val reason = String.format(MXCryptoError.UNABLE_TO_ENCRYPT_REASON, @@ -659,7 +630,7 @@ internal class DefaultCryptoService @Inject constructor( incomingRoomKeyRequestManager.onRoomKeyRequestEvent(event) } else -> { - //ignore + // ignore } } } @@ -714,7 +685,6 @@ internal class DefaultCryptoService @Inject constructor( } else { RoomMembers(realm, roomId).getJoinedRoomMemberIds() } - } return userIds } @@ -761,7 +731,6 @@ internal class DefaultCryptoService @Inject constructor( } } - /** * Upload my user's device keys. */ @@ -787,7 +756,7 @@ internal class DefaultCryptoService @Inject constructor( GlobalScope.launch(coroutineDispatchers.main) { runCatching { exportRoomKeys(password, MXMegolmExportEncryption.DEFAULT_ITERATION_COUNT) - }.fold(callback::onSuccess, callback::onFailure) + }.foldToCallback(callback) } } @@ -796,7 +765,6 @@ internal class DefaultCryptoService @Inject constructor( * * @param password the password * @param anIterationCount the encryption iteration count (0 means no encryption) - * @param callback the exported keys */ private suspend fun exportRoomKeys(password: String, anIterationCount: Int): ByteArray { return withContext(coroutineDispatchers.crypto) { @@ -824,8 +792,8 @@ internal class DefaultCryptoService @Inject constructor( progressListener: ProgressListener?, callback: MatrixCallback) { GlobalScope.launch(coroutineDispatchers.main) { - withContext(coroutineDispatchers.crypto) { - Try { + runCatching { + withContext(coroutineDispatchers.crypto) { Timber.v("## importRoomKeys starts") val t0 = System.currentTimeMillis() @@ -872,19 +840,14 @@ internal class DefaultCryptoService @Inject constructor( fun checkUnknownDevices(userIds: List, callback: MatrixCallback) { // force the refresh to ensure that the devices list is up-to-date GlobalScope.launch(coroutineDispatchers.crypto) { - runCatching { deviceListManager.downloadKeys(userIds, true) } - .fold( - { - val unknownDevices = getUnknownDevices(it) - if (unknownDevices.map.isEmpty()) { - callback.onSuccess(Unit) - } else { - // trigger an an unknown devices exception - callback.onFailure(Failure.CryptoError(MXCryptoError.UnknownDevice(unknownDevices))) - } - }, - { callback.onFailure(it) } - ) + runCatching { + val keys = deviceListManager.downloadKeys(userIds, true) + val unknownDevices = getUnknownDevices(keys) + if (unknownDevices.map.isNotEmpty()) { + // trigger an an unknown devices exception + throw Failure.CryptoError(MXCryptoError.UnknownDevice(unknownDevices)) + } + }.foldToCallback(callback) } } @@ -945,7 +908,6 @@ internal class DefaultCryptoService @Inject constructor( cryptoStore.setRoomsListBlacklistUnverifiedDevices(roomIds) } - /** * Add this room to the ones which don't encrypt messages to unverified devices. * diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/DeviceListManager.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/DeviceListManager.kt index e7cfdfe1a8..7f2a23e4c2 100755 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/DeviceListManager.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/DeviceListManager.kt @@ -17,7 +17,6 @@ package im.vector.matrix.android.internal.crypto -import android.text.TextUtils import im.vector.matrix.android.api.MatrixPatterns import im.vector.matrix.android.api.auth.data.Credentials import im.vector.matrix.android.internal.crypto.model.MXDeviceInfo @@ -27,7 +26,6 @@ import im.vector.matrix.android.internal.crypto.tasks.DownloadKeysForUsersTask import im.vector.matrix.android.internal.session.SessionScope import im.vector.matrix.android.internal.session.sync.SyncTokenStore import timber.log.Timber -import java.util.* import javax.inject.Inject // Legacy name: MXDeviceList @@ -39,13 +37,12 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM private val downloadKeysForUsersTask: DownloadKeysForUsersTask) { // HS not ready for retry - private val notReadyToRetryHS = HashSet() + private val notReadyToRetryHS = mutableSetOf() init { var isUpdated = false val deviceTrackingStatuses = cryptoStore.getDeviceTrackingStatuses().toMutableMap() - for (userId in deviceTrackingStatuses.keys) { - val status = deviceTrackingStatuses[userId]!! + for ((userId, status) in deviceTrackingStatuses) { if (TRACKING_STATUS_DOWNLOAD_IN_PROGRESS == status || TRACKING_STATUS_UNREACHABLE_SERVER == status) { // if a download was in progress when we got shut down, it isn't any more. deviceTrackingStatuses[userId] = TRACKING_STATUS_PENDING_DOWNLOAD @@ -66,7 +63,7 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM private fun canRetryKeysDownload(userId: String): Boolean { var res = false - if (!TextUtils.isEmpty(userId) && userId.contains(":")) { + if (':' in userId) { try { synchronized(notReadyToRetryHS) { res = !notReadyToRetryHS.contains(userId.substring(userId.lastIndexOf(":") + 1)) @@ -74,7 +71,6 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM } catch (e: Exception) { Timber.e(e, "## canRetryKeysDownload() failed") } - } return res @@ -120,27 +116,23 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM * @param changed the user ids list which have new devices * @param left the user ids list which left a room */ - fun handleDeviceListsChanges(changed: List?, left: List?) { + fun handleDeviceListsChanges(changed: Collection, left: Collection) { var isUpdated = false val deviceTrackingStatuses = cryptoStore.getDeviceTrackingStatuses().toMutableMap() - if (changed?.isNotEmpty() == true) { - for (userId in changed) { - if (deviceTrackingStatuses.containsKey(userId)) { - Timber.v("## invalidateUserDeviceList() : Marking device list outdated for $userId") - deviceTrackingStatuses[userId] = TRACKING_STATUS_PENDING_DOWNLOAD - isUpdated = true - } + for (userId in changed) { + if (deviceTrackingStatuses.containsKey(userId)) { + Timber.v("## invalidateUserDeviceList() : Marking device list outdated for $userId") + deviceTrackingStatuses[userId] = TRACKING_STATUS_PENDING_DOWNLOAD + isUpdated = true } } - if (left?.isNotEmpty() == true) { - for (userId in left) { - if (deviceTrackingStatuses.containsKey(userId)) { - Timber.v("## invalidateUserDeviceList() : No longer tracking device list for $userId") - deviceTrackingStatuses[userId] = TRACKING_STATUS_NOT_TRACKED - isUpdated = true - } + for (userId in left) { + if (deviceTrackingStatuses.containsKey(userId)) { + Timber.v("## invalidateUserDeviceList() : No longer tracking device list for $userId") + deviceTrackingStatuses[userId] = TRACKING_STATUS_NOT_TRACKED + isUpdated = true } } @@ -154,7 +146,7 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM * + update */ fun invalidateAllDeviceLists() { - handleDeviceListsChanges(ArrayList(cryptoStore.getDeviceTrackingStatuses().keys), null) + handleDeviceListsChanges(cryptoStore.getDeviceTrackingStatuses().keys, emptyList()) } /** @@ -164,9 +156,7 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM */ private fun onKeysDownloadFailed(userIds: List) { val deviceTrackingStatuses = cryptoStore.getDeviceTrackingStatuses().toMutableMap() - for (userId in userIds) { - deviceTrackingStatuses[userId] = TRACKING_STATUS_PENDING_DOWNLOAD - } + userIds.associateWithTo(deviceTrackingStatuses) { TRACKING_STATUS_PENDING_DOWNLOAD } cryptoStore.saveDeviceTrackingStatuses(deviceTrackingStatuses) } @@ -178,21 +168,15 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM */ private fun onKeysDownloadSucceed(userIds: List, failures: Map>?): MXUsersDevicesMap { if (failures != null) { - val keys = failures.keys - for (k in keys) { - val value = failures[k] - if (value!!.containsKey("status")) { - val statusCodeAsVoid = value["status"] - var statusCode = 0 - if (statusCodeAsVoid is Double) { - statusCode = statusCodeAsVoid.toInt() - } else if (statusCodeAsVoid is Int) { - statusCode = statusCodeAsVoid.toInt() - } - if (statusCode == 503) { - synchronized(notReadyToRetryHS) { - notReadyToRetryHS.add(k) - } + for ((k, value) in failures) { + val statusCode = when (val status = value["status"]) { + is Double -> status.toInt() + is Int -> status.toInt() + else -> 0 + } + if (statusCode == 503) { + synchronized(notReadyToRetryHS) { + notReadyToRetryHS.add(k) } } } @@ -229,11 +213,9 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM /** * Download the device keys for a list of users and stores the keys in the MXStore. * It must be called in getEncryptingThreadHandler() thread. - * The callback is called in the UI thread. * * @param userIds The users to fetch. * @param forceDownload Always download the keys even if cached. - * @param callback the asynchronous callback */ suspend fun downloadKeys(userIds: List?, forceDownload: Boolean): MXUsersDevicesMap { Timber.v("## downloadKeys() : forceDownload $forceDownload : $userIds") @@ -271,7 +253,7 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM Timber.v("## downloadKeys() : starts") val t0 = System.currentTimeMillis() val result = doKeyDownloadForUsers(downloadUsers) - Timber.v("## downloadKeys() : doKeyDownloadForUsers succeeds after " + (System.currentTimeMillis() - t0) + " ms") + Timber.v("## downloadKeys() : doKeyDownloadForUsers succeeds after ${System.currentTimeMillis() - t0} ms") result.also { it.addEntriesFromMap(stored) } @@ -304,16 +286,14 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM val devices = response.deviceKeys?.get(userId) Timber.v("## doKeyDownloadForUsers() : Got keys for $userId : $devices") if (devices != null) { - val mutableDevices = HashMap(devices) - val deviceIds = ArrayList(mutableDevices.keys) - for (deviceId in deviceIds) { + val mutableDevices = devices.toMutableMap() + for ((deviceId, deviceInfo) in devices) { // Get the potential previously store device keys for this device val previouslyStoredDeviceKeys = cryptoStore.getUserDevice(deviceId, userId) - val deviceInfo = mutableDevices[deviceId] // in some race conditions (like unit tests) // the self device must be seen as verified - if (TextUtils.equals(deviceInfo!!.deviceId, credentials.deviceId) && TextUtils.equals(userId, credentials.userId)) { + if (deviceInfo.deviceId == credentials.deviceId && userId == credentials.userId) { deviceInfo.verified = MXDeviceInfo.DEVICE_VERIFICATION_VERIFIED } // Validate received keys @@ -366,13 +346,13 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM } // Check that the user_id and device_id in the received deviceKeys are correct - if (!TextUtils.equals(deviceKeys.userId, userId)) { - Timber.e("## validateDeviceKeys() : Mismatched user_id " + deviceKeys.userId + " from " + userId + ":" + deviceId) + if (deviceKeys.userId != userId) { + Timber.e("## validateDeviceKeys() : Mismatched user_id ${deviceKeys.userId} from $userId:$deviceId") return false } - if (!TextUtils.equals(deviceKeys.deviceId, deviceId)) { - Timber.e("## validateDeviceKeys() : Mismatched device_id " + deviceKeys.deviceId + " from " + userId + ":" + deviceId) + if (deviceKeys.deviceId != deviceId) { + Timber.e("## validateDeviceKeys() : Mismatched device_id ${deviceKeys.deviceId} from $userId:$deviceId") return false } @@ -380,21 +360,21 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM val signKey = deviceKeys.keys?.get(signKeyId) if (null == signKey) { - Timber.e("## validateDeviceKeys() : Device " + userId + ":" + deviceKeys.deviceId + " has no ed25519 key") + Timber.e("## validateDeviceKeys() : Device $userId:${deviceKeys.deviceId} has no ed25519 key") return false } val signatureMap = deviceKeys.signatures?.get(userId) if (null == signatureMap) { - Timber.e("## validateDeviceKeys() : Device " + userId + ":" + deviceKeys.deviceId + " has no map for " + userId) + Timber.e("## validateDeviceKeys() : Device $userId:${deviceKeys.deviceId} has no map for $userId") return false } val signature = signatureMap[signKeyId] if (null == signature) { - Timber.e("## validateDeviceKeys() : Device " + userId + ":" + deviceKeys.deviceId + " is not signed") + Timber.e("## validateDeviceKeys() : Device $userId:${deviceKeys.deviceId} is not signed") return false } @@ -415,7 +395,7 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM } if (null != previouslyStoredDeviceKeys) { - if (!TextUtils.equals(previouslyStoredDeviceKeys.fingerprint(), signKey)) { + if (previouslyStoredDeviceKeys.fingerprint() != signKey) { // This should only happen if the list has been MITMed; we are // best off sticking with the original keys. // @@ -425,7 +405,7 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM + previouslyStoredDeviceKeys.fingerprint() + " -> " + signKey) Timber.e("## validateDeviceKeys() : $previouslyStoredDeviceKeys -> $deviceKeys") - Timber.e("## validateDeviceKeys() : " + previouslyStoredDeviceKeys.keys + " -> " + deviceKeys.keys) + Timber.e("## validateDeviceKeys() : ${previouslyStoredDeviceKeys.keys} -> ${deviceKeys.keys}") return false } @@ -439,27 +419,18 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM * This method must be called on getEncryptingThreadHandler() thread. */ suspend fun refreshOutdatedDeviceLists() { - val users = ArrayList() - val deviceTrackingStatuses = cryptoStore.getDeviceTrackingStatuses().toMutableMap() - for (userId in deviceTrackingStatuses.keys) { - if (TRACKING_STATUS_PENDING_DOWNLOAD == deviceTrackingStatuses[userId]) { - users.add(userId) - } + val users = deviceTrackingStatuses.keys.filterTo(mutableListOf()) { userId -> + TRACKING_STATUS_PENDING_DOWNLOAD == deviceTrackingStatuses[userId] } - if (users.size == 0) { + if (users.isEmpty()) { return } // update the statuses - for (userId in users) { - val status = deviceTrackingStatuses[userId] - if (null != status && TRACKING_STATUS_PENDING_DOWNLOAD == status) { - deviceTrackingStatuses.put(userId, TRACKING_STATUS_DOWNLOAD_IN_PROGRESS) - } - } + users.associateWithTo(deviceTrackingStatuses) { TRACKING_STATUS_DOWNLOAD_IN_PROGRESS } cryptoStore.saveDeviceTrackingStatuses(deviceTrackingStatuses) runCatching { @@ -506,4 +477,4 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM const val TRACKING_STATUS_UP_TO_DATE = 3 const val TRACKING_STATUS_UNREACHABLE_SERVER = 4 } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/IncomingRoomKeyRequest.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/IncomingRoomKeyRequest.kt index 056d99425e..fe1f69f904 100755 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/IncomingRoomKeyRequest.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/IncomingRoomKeyRequest.kt @@ -17,7 +17,6 @@ package im.vector.matrix.android.internal.crypto - import im.vector.matrix.android.api.session.events.model.Event import im.vector.matrix.android.api.session.events.model.toModel import im.vector.matrix.android.internal.crypto.model.rest.RoomKeyRequestBody @@ -77,4 +76,3 @@ open class IncomingRoomKeyRequest { */ constructor() } - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/IncomingRoomKeyRequestManager.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/IncomingRoomKeyRequestManager.kt index 86f7813083..3c8d70f2f1 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/IncomingRoomKeyRequestManager.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/IncomingRoomKeyRequestManager.kt @@ -16,7 +16,6 @@ package im.vector.matrix.android.internal.crypto -import android.text.TextUtils import im.vector.matrix.android.api.auth.data.Credentials import im.vector.matrix.android.api.session.crypto.keyshare.RoomKeysRequestListener import im.vector.matrix.android.api.session.events.model.Event @@ -25,7 +24,6 @@ import im.vector.matrix.android.internal.crypto.model.rest.RoomKeyShare import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore import im.vector.matrix.android.internal.session.SessionScope import timber.log.Timber -import java.util.* import javax.inject.Inject import kotlin.collections.ArrayList @@ -35,7 +33,6 @@ internal class IncomingRoomKeyRequestManager @Inject constructor( private val cryptoStore: IMXCryptoStore, private val roomDecryptorProvider: RoomDecryptorProvider) { - // list of IncomingRoomKeyRequests/IncomingRoomKeyRequestCancellations // we received in the current sync. private val receivedRoomKeyRequests = ArrayList() @@ -59,7 +56,7 @@ internal class IncomingRoomKeyRequestManager @Inject constructor( when (roomKeyShare?.action) { RoomKeyShare.ACTION_SHARE_REQUEST -> receivedRoomKeyRequests.add(IncomingRoomKeyRequest(event)) RoomKeyShare.ACTION_SHARE_CANCELLATION -> receivedRoomKeyRequestCancellations.add(IncomingRoomKeyRequestCancellation(event)) - else -> Timber.e("## onRoomKeyRequestEvent() : unsupported action " + roomKeyShare?.action) + else -> Timber.e("## onRoomKeyRequestEvent() : unsupported action ${roomKeyShare?.action}") } } @@ -69,7 +66,7 @@ internal class IncomingRoomKeyRequestManager @Inject constructor( * It must be called on CryptoThread */ fun processReceivedRoomKeyRequests() { - val roomKeyRequestsToProcess = ArrayList(receivedRoomKeyRequests) + val roomKeyRequestsToProcess = receivedRoomKeyRequests.toList() receivedRoomKeyRequests.clear() for (request in roomKeyRequestsToProcess) { val userId = request.userId @@ -78,7 +75,7 @@ internal class IncomingRoomKeyRequestManager @Inject constructor( val roomId = body!!.roomId val alg = body.algorithm - Timber.v("m.room_key_request from " + userId + ":" + deviceId + " for " + roomId + " / " + body.sessionId + " id " + request.requestId) + Timber.v("m.room_key_request from $userId:$deviceId for $roomId / ${body.sessionId} id ${request.requestId}") if (userId == null || credentials.userId != userId) { // TODO: determine if we sent this device the keys already: in Timber.e("## processReceivedRoomKeyRequests() : Ignoring room key request from other user for now") @@ -93,12 +90,12 @@ internal class IncomingRoomKeyRequestManager @Inject constructor( continue } if (!decryptor.hasKeysForKeyRequest(request)) { - Timber.e("## processReceivedRoomKeyRequests() : room key request for unknown session " + body.sessionId!!) + Timber.e("## processReceivedRoomKeyRequests() : room key request for unknown session ${body.sessionId!!}") cryptoStore.deleteIncomingRoomKeyRequest(request) continue } - if (TextUtils.equals(deviceId, credentials.deviceId) && TextUtils.equals(credentials.userId, userId)) { + if (credentials.deviceId == deviceId && credentials.userId == userId) { Timber.v("## processReceivedRoomKeyRequests() : oneself device - ignored") cryptoStore.deleteIncomingRoomKeyRequest(request) continue @@ -133,7 +130,7 @@ internal class IncomingRoomKeyRequestManager @Inject constructor( var receivedRoomKeyRequestCancellations: List? = null synchronized(this.receivedRoomKeyRequestCancellations) { - if (!this.receivedRoomKeyRequestCancellations.isEmpty()) { + if (this.receivedRoomKeyRequestCancellations.isNotEmpty()) { receivedRoomKeyRequestCancellations = this.receivedRoomKeyRequestCancellations.toList() this.receivedRoomKeyRequestCancellations.clear() } @@ -166,12 +163,10 @@ internal class IncomingRoomKeyRequestManager @Inject constructor( } catch (e: Exception) { Timber.e(e, "## onRoomKeyRequest() failed") } - } } } - /** * A room key request cancellation has been received. * @@ -185,7 +180,6 @@ internal class IncomingRoomKeyRequestManager @Inject constructor( } catch (e: Exception) { Timber.e(e, "## onRoomKeyRequestCancellation() failed") } - } } } @@ -201,5 +195,4 @@ internal class IncomingRoomKeyRequestManager @Inject constructor( roomKeysRequestListeners.remove(listener) } } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/MXCryptoAlgorithms.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/MXCryptoAlgorithms.kt index 8f42c422df..92b6adabc5 100755 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/MXCryptoAlgorithms.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/MXCryptoAlgorithms.kt @@ -55,4 +55,4 @@ internal object MXCryptoAlgorithms { fun supportedAlgorithms(): List { return listOf(MXCRYPTO_ALGORITHM_MEGOLM, MXCRYPTO_ALGORITHM_OLM) } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/MXMegolmExportEncryption.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/MXMegolmExportEncryption.kt index b9cb59a0f5..0aa7a15ce2 100755 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/MXMegolmExportEncryption.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/MXMegolmExportEncryption.kt @@ -16,20 +16,19 @@ package im.vector.matrix.android.internal.crypto -import android.text.TextUtils import android.util.Base64 import im.vector.matrix.android.internal.extensions.toUnsignedInt import timber.log.Timber import java.io.ByteArrayOutputStream import java.nio.charset.Charset import java.security.SecureRandom -import java.util.* import javax.crypto.Cipher import javax.crypto.Mac import javax.crypto.spec.IvParameterSpec import javax.crypto.spec.SecretKeySpec import kotlin.experimental.and import kotlin.experimental.xor +import kotlin.math.min /** * Utility class to import/export the crypto data @@ -51,7 +50,7 @@ object MXMegolmExportEncryption { * @return the AES key */ private fun getAesKey(keyBits: ByteArray): ByteArray { - return Arrays.copyOfRange(keyBits, 0, 32) + return keyBits.copyOfRange(0, 32) } /** @@ -61,7 +60,7 @@ object MXMegolmExportEncryption { * @return the Hmac key. */ private fun getHmacKey(keyBits: ByteArray): ByteArray { - return Arrays.copyOfRange(keyBits, 32, keyBits.size) + return keyBits.copyOfRange(32, keyBits.size) } /** @@ -77,7 +76,7 @@ object MXMegolmExportEncryption { val body = unpackMegolmKeyFile(data) // check we have a version byte - if (null == body || body.size == 0) { + if (null == body || body.isEmpty()) { Timber.e("## decryptMegolmKeyFile() : Invalid file: too short") throw Exception("Invalid file: too short") } @@ -93,27 +92,27 @@ object MXMegolmExportEncryption { throw Exception("Invalid file: too short") } - if (TextUtils.isEmpty(password)) { + if (password.isEmpty()) { throw Exception("Empty password is not supported") } - val salt = Arrays.copyOfRange(body, 1, 1 + 16) - val iv = Arrays.copyOfRange(body, 17, 17 + 16) + val salt = body.copyOfRange(1, 1 + 16) + val iv = body.copyOfRange(17, 17 + 16) val iterations = (body[33].toUnsignedInt() shl 24) or (body[34].toUnsignedInt() shl 16) or (body[35].toUnsignedInt() shl 8) or body[36].toUnsignedInt() - val ciphertext = Arrays.copyOfRange(body, 37, 37 + ciphertextLength) - val hmac = Arrays.copyOfRange(body, body.size - 32, body.size) + val ciphertext = body.copyOfRange(37, 37 + ciphertextLength) + val hmac = body.copyOfRange(body.size - 32, body.size) val deriveKey = deriveKeys(salt, iterations, password) - val toVerify = Arrays.copyOfRange(body, 0, body.size - 32) + val toVerify = body.copyOfRange(0, body.size - 32) val macKey = SecretKeySpec(getHmacKey(deriveKey), "HmacSHA256") val mac = Mac.getInstance("HmacSHA256") mac.init(macKey) val digest = mac.doFinal(toVerify) - if (!Arrays.equals(hmac, digest)) { + if (!hmac.contentEquals(digest)) { Timber.e("## decryptMegolmKeyFile() : Authentication check failed: incorrect password?") throw Exception("Authentication check failed: incorrect password?") } @@ -146,7 +145,7 @@ object MXMegolmExportEncryption { @Throws(Exception::class) @JvmOverloads fun encryptMegolmKeyFile(data: String, password: String, kdf_rounds: Int = DEFAULT_ITERATION_COUNT): ByteArray { - if (TextUtils.isEmpty(password)) { + if (password.isEmpty()) { throw Exception("Empty password is not supported") } @@ -196,7 +195,7 @@ object MXMegolmExportEncryption { System.arraycopy(cipherArray, 0, resultBuffer, idx, cipherArray.size) idx += cipherArray.size - val toSign = Arrays.copyOfRange(resultBuffer, 0, idx) + val toSign = resultBuffer.copyOfRange(0, idx) val macKey = SecretKeySpec(getHmacKey(deriveKey), "HmacSHA256") val mac = Mac.getInstance("HmacSHA256") @@ -234,7 +233,7 @@ object MXMegolmExportEncryption { // start the next line after the newline lineStart = lineEnd + 1 - if (TextUtils.equals(line, HEADER_LINE)) { + if (line == HEADER_LINE) { break } } @@ -244,15 +243,13 @@ object MXMegolmExportEncryption { // look for the end line while (true) { val lineEnd = fileStr.indexOf('\n', lineStart) - val line: String - - if (lineEnd < 0) { - line = fileStr.substring(lineStart).trim() + val line = if (lineEnd < 0) { + fileStr.substring(lineStart) } else { - line = fileStr.substring(lineStart, lineEnd).trim() - } + fileStr.substring(lineStart, lineEnd) + }.trim() - if (TextUtils.equals(line, TRAILER_LINE)) { + if (line == TRAILER_LINE) { break } @@ -290,7 +287,7 @@ object MXMegolmExportEncryption { for (i in 1..nLines) { outStream.write("\n".toByteArray()) - val len = Math.min(LINE_LENGTH, data.size - o) + val len = min(LINE_LENGTH, data.size - o) outStream.write(Base64.encode(data, o, len, Base64.DEFAULT)) o += LINE_LENGTH } @@ -318,7 +315,7 @@ object MXMegolmExportEncryption { // it is simpler than the generic algorithm because the expected key length is equal to the mac key length. // noticed as dklen/hlen val prf = Mac.getInstance("HmacSHA512") - prf.init(SecretKeySpec(password.toByteArray(charset("UTF-8")), "HmacSHA512")) + prf.init(SecretKeySpec(password.toByteArray(Charsets.UTF_8), "HmacSHA512")) // 512 bits key length val key = ByteArray(64) @@ -326,8 +323,7 @@ object MXMegolmExportEncryption { // U1 = PRF(Password, Salt || INT_32_BE(i)) prf.update(salt) - val int32BE = ByteArray(4) - Arrays.fill(int32BE, 0.toByte()) + val int32BE = ByteArray(4) { 0.toByte() } int32BE[3] = 1.toByte() prf.update(int32BE) prf.doFinal(Uc, 0) @@ -346,7 +342,7 @@ object MXMegolmExportEncryption { } } - Timber.v("## deriveKeys() : " + iterations + " in " + (System.currentTimeMillis() - t0) + " ms") + Timber.v("## deriveKeys() : $iterations in ${System.currentTimeMillis() - t0} ms") return key } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/MXOlmDevice.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/MXOlmDevice.kt index 7c5131fcce..68aaaf3831 100755 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/MXOlmDevice.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/MXOlmDevice.kt @@ -17,7 +17,6 @@ package im.vector.matrix.android.internal.crypto -import android.text.TextUtils import im.vector.matrix.android.api.session.crypto.MXCryptoError import im.vector.matrix.android.api.util.JSON_DICT_PARAMETERIZED_TYPE import im.vector.matrix.android.api.util.JsonDict @@ -33,7 +32,6 @@ import im.vector.matrix.android.internal.util.convertToUTF8 import org.matrix.olm.* import timber.log.Timber import java.net.URLEncoder -import java.util.* import javax.inject.Inject // The libolm wrapper. @@ -94,7 +92,6 @@ internal class MXOlmDevice @Inject constructor( } catch (e: Exception) { Timber.e(e, "MXOlmDevice : cannot initialize olmAccount") } - } else { Timber.v("MXOlmDevice : use an existing account") } @@ -217,7 +214,6 @@ internal class MXOlmDevice @Inject constructor( Timber.v("## createOutboundSession() ; olmSession.sessionIdentifier: $sessionIdentifier") return sessionIdentifier - } catch (e: Exception) { Timber.e(e, "## createOutboundSession() failed") @@ -236,7 +232,6 @@ internal class MXOlmDevice @Inject constructor( * @return {{payload: string, session_id: string}} decrypted payload, and session id of new session. */ fun createInboundSession(theirDeviceIdentityKey: String, messageType: Int, ciphertext: String): Map? { - Timber.v("## createInboundSession() : theirIdentityKey: $theirDeviceIdentityKey") var olmSession: OlmSession? = null @@ -250,7 +245,7 @@ internal class MXOlmDevice @Inject constructor( return null } - Timber.v("## createInboundSession() : sessionId: " + olmSession.sessionIdentifier()) + Timber.v("## createInboundSession() : sessionId: ${olmSession.sessionIdentifier()}") try { olmAccount!!.removeOneTimeKeys(olmSession) @@ -262,7 +257,7 @@ internal class MXOlmDevice @Inject constructor( Timber.v("## createInboundSession() : ciphertext: $ciphertext") try { val sha256 = olmUtility!!.sha256(URLEncoder.encode(ciphertext, "utf-8")) - Timber.v("## createInboundSession() :ciphertext: SHA256:" + sha256) + Timber.v("## createInboundSession() :ciphertext: SHA256: $sha256") } catch (e: Exception) { Timber.e(e, "## createInboundSession() :ciphertext: cannot encode ciphertext") } @@ -343,7 +338,7 @@ internal class MXOlmDevice @Inject constructor( if (olmSessionWrapper != null) { try { Timber.v("## encryptMessage() : olmSession.sessionIdentifier: $sessionId") - //Timber.v("## encryptMessage() : payloadString: " + payloadString); + // Timber.v("## encryptMessage() : payloadString: " + payloadString); olmMessage = olmSessionWrapper.olmSession.encryptMessage(payloadString) store.storeSession(olmSessionWrapper, theirDeviceIdentityKey) @@ -352,9 +347,8 @@ internal class MXOlmDevice @Inject constructor( res["body"] = olmMessage.mCipherText res["type"] = olmMessage.mType } catch (e: Exception) { - Timber.e(e, "## encryptMessage() : failed " + e.message) + Timber.e(e, "## encryptMessage() : failed") } - } return res @@ -384,9 +378,8 @@ internal class MXOlmDevice @Inject constructor( olmSessionWrapper.onMessageReceived() store.storeSession(olmSessionWrapper, theirDeviceIdentityKey) } catch (e: Exception) { - Timber.e(e, "## decryptMessage() : decryptMessage failed " + e.message) + Timber.e(e, "## decryptMessage() : decryptMessage failed") } - } return payloadString @@ -410,7 +403,6 @@ internal class MXOlmDevice @Inject constructor( return null != olmSessionWrapper && olmSessionWrapper.olmSession.matchesInboundSession(ciphertext) } - // Outbound group session /** @@ -425,7 +417,7 @@ internal class MXOlmDevice @Inject constructor( outboundGroupSessionStore[session.sessionIdentifier()] = session return session.sessionIdentifier() } catch (e: Exception) { - Timber.e(e, "createOutboundGroupSession " + e.message) + Timber.e(e, "createOutboundGroupSession") session?.releaseSession() } @@ -440,13 +432,12 @@ internal class MXOlmDevice @Inject constructor( * @return the base64-encoded secret key. */ fun getSessionKey(sessionId: String): String? { - if (!TextUtils.isEmpty(sessionId)) { + if (sessionId.isNotEmpty()) { try { return outboundGroupSessionStore[sessionId]!!.sessionKey() } catch (e: Exception) { - Timber.e(e, "## getSessionKey() : failed " + e.message) + Timber.e(e, "## getSessionKey() : failed") } - } return null } @@ -458,7 +449,7 @@ internal class MXOlmDevice @Inject constructor( * @return the current chain index. */ fun getMessageIndex(sessionId: String): Int { - return if (!TextUtils.isEmpty(sessionId)) { + return if (sessionId.isNotEmpty()) { outboundGroupSessionStore[sessionId]!!.messageIndex() } else 0 } @@ -471,13 +462,12 @@ internal class MXOlmDevice @Inject constructor( * @return ciphertext */ fun encryptGroupMessage(sessionId: String, payloadString: String): String? { - if (!TextUtils.isEmpty(sessionId) && !TextUtils.isEmpty(payloadString)) { + if (sessionId.isNotEmpty() && payloadString.isNotEmpty()) { try { return outboundGroupSessionStore[sessionId]!!.encryptMessage(payloadString) } catch (e: Exception) { - Timber.e(e, "## encryptGroupMessage() : failed " + e.message) + Timber.e(e, "## encryptGroupMessage() : failed") } - } return null } @@ -513,7 +503,7 @@ internal class MXOlmDevice @Inject constructor( val existingFirstKnown = it.firstKnownIndex!! val newKnownFirstIndex = session.firstKnownIndex - //If our existing session is better we keep it + // If our existing session is better we keep it if (newKnownFirstIndex != null && existingFirstKnown <= newKnownFirstIndex) { session.olmInboundGroupSession?.releaseSession() return false @@ -531,7 +521,7 @@ internal class MXOlmDevice @Inject constructor( } try { - if (!TextUtils.equals(session.olmInboundGroupSession!!.sessionIdentifier(), sessionId)) { + if (session.olmInboundGroupSession!!.sessionIdentifier() != sessionId) { Timber.e("## addInboundGroupSession : ERROR: Mismatched group session ID from senderKey: $senderKey") session.olmInboundGroupSession!!.releaseSession() return false @@ -562,7 +552,6 @@ internal class MXOlmDevice @Inject constructor( val sessions = ArrayList(megolmSessionsData.size) for (megolmSessionData in megolmSessionsData) { - val sessionId = megolmSessionData.sessionId val senderKey = megolmSessionData.senderKey val roomId = megolmSessionData.roomId @@ -582,8 +571,8 @@ internal class MXOlmDevice @Inject constructor( } try { - if (!TextUtils.equals(session.olmInboundGroupSession?.sessionIdentifier(), sessionId)) { - Timber.e("## importInboundGroupSession : ERROR: Mismatched group session ID from senderKey: " + senderKey!!) + if (session.olmInboundGroupSession?.sessionIdentifier() != sessionId) { + Timber.e("## importInboundGroupSession : ERROR: Mismatched group session ID from senderKey: $senderKey") if (session.olmInboundGroupSession != null) session.olmInboundGroupSession!!.releaseSession() continue } @@ -601,7 +590,7 @@ internal class MXOlmDevice @Inject constructor( // For now we just ignore updates. TODO: implement something here if (it.firstKnownIndex!! <= session.firstKnownIndex!!) { - //Ignore this, keep existing + // Ignore this, keep existing session.olmInboundGroupSession!!.releaseSession() } else { sessions.add(session) @@ -652,9 +641,8 @@ internal class MXOlmDevice @Inject constructor( // 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 == session.roomId) { - var decryptResult: OlmInboundGroupSession.DecryptMessageResult? = null - try { - decryptResult = session.olmInboundGroupSession!!.decryptMessage(body) + val decryptResult = try { + session.olmInboundGroupSession!!.decryptMessage(body) } catch (e: OlmException) { Timber.e(e, "## decryptGroupMessage () : decryptMessage failed") throw MXCryptoError.OlmError(e) @@ -747,7 +735,6 @@ internal class MXOlmDevice @Inject constructor( return if (theirDeviceIdentityKey.isEmpty() || sessionId.isEmpty()) null else { store.getDeviceSession(sessionId, theirDeviceIdentityKey) } - } /** @@ -769,7 +756,7 @@ internal class MXOlmDevice @Inject constructor( if (session != 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 (!TextUtils.equals(roomId, session.roomId)) { + if (roomId != session.roomId) { val errorDescription = String.format(MXCryptoError.INBOUND_SESSION_MISMATCH_ROOM_ID_REASON, roomId, session.roomId) Timber.e("## getInboundGroupSession() : $errorDescription") throw MXCryptoError.Base(MXCryptoError.ErrorType.INBOUND_SESSION_MISMATCH_ROOM_ID, errorDescription) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/MyDeviceInfoHolder.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/MyDeviceInfoHolder.kt index 4223983298..f93245de12 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/MyDeviceInfoHolder.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/MyDeviceInfoHolder.kt @@ -16,12 +16,10 @@ package im.vector.matrix.android.internal.crypto -import android.text.TextUtils import im.vector.matrix.android.api.auth.data.Credentials import im.vector.matrix.android.internal.crypto.model.MXDeviceInfo import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore import im.vector.matrix.android.internal.session.SessionScope -import java.util.* import javax.inject.Inject @SessionScope @@ -42,11 +40,11 @@ internal class MyDeviceInfoHolder @Inject constructor( init { val keys = HashMap() - if (!TextUtils.isEmpty(olmDevice.deviceEd25519Key)) { + if (!olmDevice.deviceEd25519Key.isNullOrEmpty()) { keys["ed25519:" + credentials.deviceId] = olmDevice.deviceEd25519Key!! } - if (!TextUtils.isEmpty(olmDevice.deviceCurve25519Key)) { + if (!olmDevice.deviceCurve25519Key.isNullOrEmpty()) { keys["curve25519:" + credentials.deviceId] = olmDevice.deviceCurve25519Key!! } @@ -58,16 +56,10 @@ internal class MyDeviceInfoHolder @Inject constructor( // Add our own deviceinfo to the store val endToEndDevicesForUser = cryptoStore.getUserDevices(credentials.userId) - val myDevices: MutableMap - - if (null != endToEndDevicesForUser) { - myDevices = HashMap(endToEndDevicesForUser) - } else { - myDevices = HashMap() - } + val myDevices = endToEndDevicesForUser.orEmpty().toMutableMap() myDevices[myDevice.deviceId] = myDevice cryptoStore.storeUserDevices(credentials.userId, myDevices) } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/NewSessionListener.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/NewSessionListener.kt index 7881b1ea7f..e113e64146 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/NewSessionListener.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/NewSessionListener.kt @@ -15,7 +15,6 @@ */ package im.vector.matrix.android.internal.crypto - interface NewSessionListener { fun onNewSession(roomId: String?, senderKey: String, sessionId: String) -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/ObjectSigner.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/ObjectSigner.kt index 625f81de86..be15f3753e 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/ObjectSigner.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/ObjectSigner.kt @@ -42,13 +42,11 @@ internal class ObjectSigner @Inject constructor(private val credentials: Credent val content = HashMap() - content["ed25519:" + credentials.deviceId] = olmDevice.signMessage(strToSign) - ?: "" //null reported by rageshake if happens during logout + ?: "" // null reported by rageshake if happens during logout result[credentials.userId] = content return result } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/OneTimeKeysUploader.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/OneTimeKeysUploader.kt index f0d7662f0f..e6b57d149f 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/OneTimeKeysUploader.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/OneTimeKeysUploader.kt @@ -24,8 +24,9 @@ import im.vector.matrix.android.internal.session.SessionScope import im.vector.matrix.android.internal.util.JsonCanonicalizer import org.matrix.olm.OlmAccount import timber.log.Timber -import java.util.* import javax.inject.Inject +import kotlin.math.floor +import kotlin.math.min @SessionScope internal class OneTimeKeysUploader @Inject constructor( @@ -53,7 +54,6 @@ internal class OneTimeKeysUploader @Inject constructor( oneTimeKeyCount = currentCount } - /** * Check if the OTK must be uploaded. */ @@ -78,7 +78,7 @@ internal class OneTimeKeysUploader @Inject constructor( // If we run out of slots when generating new keys then olm will // discard the oldest private keys first. This will eventually clean // out stale private keys that won't receive a message. - val keyLimit = Math.floor(maxOneTimeKeys / 2.0).toInt() + val keyLimit = floor(maxOneTimeKeys / 2.0).toInt() if (oneTimeKeyCount != null) { uploadOTK(oneTimeKeyCount!!, keyLimit) } else { @@ -117,7 +117,7 @@ internal class OneTimeKeysUploader @Inject constructor( // If we don't need to generate any more keys then we are done. return } - val keysThisLoop = Math.min(keyLimit - keyCount, ONE_TIME_KEY_GENERATION_MAX_NUMBER) + val keysThisLoop = min(keyLimit - keyCount, ONE_TIME_KEY_GENERATION_MAX_NUMBER) olmDevice.generateOneTimeKeys(keysThisLoop) val response = uploadOneTimeKeys() if (response.hasOneTimeKeyCountsForAlgorithm(MXKey.KEY_SIGNED_CURVE_25519_TYPE)) { @@ -133,14 +133,14 @@ internal class OneTimeKeysUploader @Inject constructor( */ private suspend fun uploadOneTimeKeys(): KeysUploadResponse { val oneTimeKeys = olmDevice.getOneTimeKeys() - val oneTimeJson = HashMap() + val oneTimeJson = mutableMapOf() val curve25519Map = oneTimeKeys?.get(OlmAccount.JSON_KEY_ONE_TIME_KEY) if (null != curve25519Map) { - for (key_id in curve25519Map.keys) { - val k = HashMap() - k["key"] = curve25519Map.getValue(key_id) + for ((key_id, value) in curve25519Map) { + val k = mutableMapOf() + k["key"] = value // the key is also signed val canonicalJson = JsonCanonicalizer.getCanonicalJson(Map::class.java, k) @@ -170,4 +170,4 @@ internal class OneTimeKeysUploader @Inject constructor( // frequency with which to check & upload one-time keys private const val ONE_TIME_KEY_UPLOAD_PERIOD = (60 * 1000).toLong() // one minute } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/OutgoingRoomKeyRequest.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/OutgoingRoomKeyRequest.kt index 89de5a078b..a66b0242ec 100755 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/OutgoingRoomKeyRequest.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/OutgoingRoomKeyRequest.kt @@ -116,4 +116,3 @@ class OutgoingRoomKeyRequest( } } } - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/OutgoingRoomKeyRequestManager.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/OutgoingRoomKeyRequestManager.kt index c0702f70e5..89a27c9463 100755 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/OutgoingRoomKeyRequestManager.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/OutgoingRoomKeyRequestManager.kt @@ -90,7 +90,6 @@ internal class OutgoingRoomKeyRequestManager @Inject constructor( val req = cryptoStore.getOrAddOutgoingRoomKeyRequest( OutgoingRoomKeyRequest(requestBody, recipients, makeTxnId(), OutgoingRoomKeyRequest.RequestState.UNSENT)) - if (req?.state == OutgoingRoomKeyRequest.RequestState.UNSENT) { startTimer() } @@ -154,7 +153,6 @@ internal class OutgoingRoomKeyRequestManager @Inject constructor( } } - /** * Start the background timer to send queued requests, if the timer isn't already running. */ @@ -261,7 +259,6 @@ internal class OutgoingRoomKeyRequestManager @Inject constructor( startTimer() } - override fun onSuccess(data: Unit) { Timber.v("## sendOutgoingRoomKeyRequestCancellation() : done") val resend = request.state === OutgoingRoomKeyRequest.RequestState.CANCELLATION_PENDING_AND_WILL_RESEND @@ -312,6 +309,5 @@ internal class OutgoingRoomKeyRequestManager @Inject constructor( private const val SEND_KEY_REQUESTS_DELAY_MS = 500 private val BACKGROUND_HANDLER = createBackgroundHandler("OutgoingRoomKeyRequest") - } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/RoomDecryptorProvider.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/RoomDecryptorProvider.kt index 3dd7b932f9..a17a524923 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/RoomDecryptorProvider.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/RoomDecryptorProvider.kt @@ -16,13 +16,11 @@ package im.vector.matrix.android.internal.crypto -import android.text.TextUtils import im.vector.matrix.android.internal.crypto.algorithms.IMXDecrypting import im.vector.matrix.android.internal.crypto.algorithms.megolm.MXMegolmDecryptionFactory import im.vector.matrix.android.internal.crypto.algorithms.olm.MXOlmDecryptionFactory import im.vector.matrix.android.internal.session.SessionScope import timber.log.Timber -import java.util.* import javax.inject.Inject @SessionScope @@ -62,10 +60,8 @@ internal class RoomDecryptorProvider @Inject constructor( } if (roomId != null && roomId.isNotEmpty()) { synchronized(roomDecryptors) { - if (!roomDecryptors.containsKey(roomId)) { - roomDecryptors[roomId] = HashMap() - } - val alg = roomDecryptors[roomId]?.get(algorithm) + val decryptors = roomDecryptors.getOrPut(roomId) { mutableMapOf() } + val alg = decryptors[algorithm] if (alg != null) { return alg } @@ -76,12 +72,12 @@ internal class RoomDecryptorProvider @Inject constructor( val alg = when (algorithm) { MXCRYPTO_ALGORITHM_MEGOLM -> megolmDecryptionFactory.create().apply { this.newSessionListener = object : NewSessionListener { - override fun onNewSession(rid: String?, senderKey: String, sessionId: String) { + override fun onNewSession(roomId: String?, senderKey: String, sessionId: String) { + // PR reviewer: the parameter has been renamed so is now in conflict with the parameter of getOrCreateRoomDecryptor newSessionListeners.forEach { try { it.onNewSession(roomId, senderKey, sessionId) } catch (e: Throwable) { - } } } @@ -89,7 +85,7 @@ internal class RoomDecryptorProvider @Inject constructor( } else -> olmDecryptionFactory.create() } - if (roomId != null && !TextUtils.isEmpty(roomId)) { + if (!roomId.isNullOrEmpty()) { synchronized(roomDecryptors) { roomDecryptors[roomId]?.put(algorithm, alg) } @@ -105,4 +101,4 @@ internal class RoomDecryptorProvider @Inject constructor( } return roomDecryptors[roomId]?.get(algorithm) } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/actions/EnsureOlmSessionsForDevicesAction.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/actions/EnsureOlmSessionsForDevicesAction.kt index 7a56f46bd1..0283d3c85b 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/actions/EnsureOlmSessionsForDevicesAction.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/actions/EnsureOlmSessionsForDevicesAction.kt @@ -16,7 +16,6 @@ package im.vector.matrix.android.internal.crypto.actions -import android.text.TextUtils import im.vector.matrix.android.internal.crypto.MXOlmDevice import im.vector.matrix.android.internal.crypto.model.MXDeviceInfo import im.vector.matrix.android.internal.crypto.model.MXKey @@ -24,30 +23,24 @@ import im.vector.matrix.android.internal.crypto.model.MXOlmSessionResult import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap import im.vector.matrix.android.internal.crypto.tasks.ClaimOneTimeKeysForUsersDeviceTask import timber.log.Timber -import java.util.* import javax.inject.Inject internal class EnsureOlmSessionsForDevicesAction @Inject constructor(private val olmDevice: MXOlmDevice, private val oneTimeKeysForUsersDeviceTask: ClaimOneTimeKeysForUsersDeviceTask) { - suspend fun handle(devicesByUser: Map>): MXUsersDevicesMap { val devicesWithoutSession = ArrayList() val results = MXUsersDevicesMap() - val userIds = devicesByUser.keys - - for (userId in userIds) { - val deviceInfos = devicesByUser[userId] - - for (deviceInfo in deviceInfos!!) { + for ((userId, deviceInfos) in devicesByUser) { + for (deviceInfo in deviceInfos) { val deviceId = deviceInfo.deviceId val key = deviceInfo.identityKey() val sessionId = olmDevice.getSessionId(key!!) - if (TextUtils.isEmpty(sessionId)) { + if (sessionId.isNullOrEmpty()) { devicesWithoutSession.add(deviceInfo) } @@ -80,9 +73,8 @@ internal class EnsureOlmSessionsForDevicesAction @Inject constructor(private val val claimParams = ClaimOneTimeKeysForUsersDeviceTask.Params(usersDevicesToClaim) val oneTimeKeys = oneTimeKeysForUsersDeviceTask.execute(claimParams) Timber.v("## claimOneTimeKeysForUsersDevices() : keysClaimResponse.oneTimeKeys: $oneTimeKeys") - for (userId in userIds) { - val deviceInfos = devicesByUser[userId] - for (deviceInfo in deviceInfos!!) { + for ((userId, deviceInfos) in devicesByUser) { + for (deviceInfo in deviceInfos) { var oneTimeKey: MXKey? = null val deviceIds = oneTimeKeys.getUserDeviceIds(userId) if (null != deviceIds) { @@ -117,24 +109,22 @@ internal class EnsureOlmSessionsForDevicesAction @Inject constructor(private val val signKeyId = "ed25519:$deviceId" val signature = oneTimeKey.signatureForUserId(userId, signKeyId) - if (!TextUtils.isEmpty(signature) && !TextUtils.isEmpty(deviceInfo.fingerprint())) { + if (!signature.isNullOrEmpty() && !deviceInfo.fingerprint().isNullOrEmpty()) { var isVerified = false var errorMessage: String? = null - if (signature != null) { - try { - olmDevice.verifySignature(deviceInfo.fingerprint()!!, oneTimeKey.signalableJSONDictionary(), signature) - isVerified = true - } catch (e: Exception) { - errorMessage = e.message - } + try { + olmDevice.verifySignature(deviceInfo.fingerprint()!!, oneTimeKey.signalableJSONDictionary(), signature) + isVerified = true + } catch (e: Exception) { + errorMessage = e.message } // Check one-time key signature if (isVerified) { sessionId = olmDevice.createOutboundSession(deviceInfo.identityKey()!!, oneTimeKey.value) - if (!TextUtils.isEmpty(sessionId)) { + if (!sessionId.isNullOrEmpty()) { Timber.v("## verifyKeyAndStartSession() : Started new sessionid " + sessionId + " for device " + deviceInfo + "(theirOneTimeKey: " + oneTimeKey.value + ")") } else { @@ -149,5 +139,4 @@ internal class EnsureOlmSessionsForDevicesAction @Inject constructor(private val return sessionId } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/actions/EnsureOlmSessionsForUsersAction.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/actions/EnsureOlmSessionsForUsersAction.kt index f929859d76..0c649cce89 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/actions/EnsureOlmSessionsForUsersAction.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/actions/EnsureOlmSessionsForUsersAction.kt @@ -16,14 +16,11 @@ package im.vector.matrix.android.internal.crypto.actions -import android.text.TextUtils import im.vector.matrix.android.internal.crypto.MXOlmDevice -import im.vector.matrix.android.internal.crypto.model.MXDeviceInfo import im.vector.matrix.android.internal.crypto.model.MXOlmSessionResult import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore import timber.log.Timber -import java.util.* import javax.inject.Inject internal class EnsureOlmSessionsForUsersAction @Inject constructor(private val olmDevice: MXOlmDevice, @@ -36,29 +33,16 @@ internal class EnsureOlmSessionsForUsersAction @Inject constructor(private val o */ suspend fun handle(users: List): MXUsersDevicesMap { Timber.v("## ensureOlmSessionsForUsers() : ensureOlmSessionsForUsers $users") - val devicesByUser = HashMap>() - - for (userId in users) { - devicesByUser[userId] = ArrayList() - + val devicesByUser = users.associateWith { userId -> val devices = cryptoStore.getUserDevices(userId)?.values ?: emptyList() - for (device in devices) { - val key = device.identityKey() - - if (TextUtils.equals(key, olmDevice.deviceCurve25519Key)) { - // Don't bother setting up session to ourself - continue - } - - if (device.isVerified) { - // Don't bother setting up sessions with blocked users - continue - } - - devicesByUser[userId]!!.add(device) + devices.filter { + // Don't bother setting up session to ourself + it.identityKey() != olmDevice.deviceCurve25519Key + // Don't bother setting up sessions with blocked users + && !it.isVerified } } return ensureOlmSessionsForDevicesAction.handle(devicesByUser) } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/actions/MegolmSessionDataImporter.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/actions/MegolmSessionDataImporter.kt index 9d345dfbc3..62b4f1b851 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/actions/MegolmSessionDataImporter.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/actions/MegolmSessionDataImporter.kt @@ -112,4 +112,4 @@ internal class MegolmSessionDataImporter @Inject constructor(private val olmDevi return ImportRoomKeysResult(totalNumbersOfKeys, totalNumbersOfImportedKeys) } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/actions/MessageEncrypter.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/actions/MessageEncrypter.kt index 3328de0eaf..ebe219600d 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/actions/MessageEncrypter.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/actions/MessageEncrypter.kt @@ -16,7 +16,6 @@ package im.vector.matrix.android.internal.crypto.actions -import android.text.TextUtils import im.vector.matrix.android.api.auth.data.Credentials import im.vector.matrix.android.internal.crypto.MXCRYPTO_ALGORITHM_OLM import im.vector.matrix.android.internal.crypto.MXOlmDevice @@ -25,7 +24,6 @@ import im.vector.matrix.android.internal.crypto.model.rest.EncryptedMessage import im.vector.matrix.android.internal.util.JsonCanonicalizer import im.vector.matrix.android.internal.util.convertToUTF8 import timber.log.Timber -import java.util.* import javax.inject.Inject internal class MessageEncrypter @Inject constructor(private val credentials: Credentials, @@ -40,18 +38,12 @@ internal class MessageEncrypter @Inject constructor(private val credentials: Cre * @return the content for an m.room.encrypted event. */ fun encryptMessage(payloadFields: Map, deviceInfos: List): EncryptedMessage { - val deviceInfoParticipantKey = HashMap() - val participantKeys = ArrayList() + val deviceInfoParticipantKey = deviceInfos.associateBy { it.identityKey()!! } - for (di in deviceInfos) { - participantKeys.add(di.identityKey()!!) - deviceInfoParticipantKey[di.identityKey()!!] = di - } - - val payloadJson = HashMap(payloadFields) + val payloadJson = payloadFields.toMutableMap() payloadJson["sender"] = credentials.userId - payloadJson["sender_device"] = credentials.deviceId + payloadJson["sender_device"] = credentials.deviceId!! // Include the Ed25519 key so that the recipient knows what // device this message came from. @@ -67,31 +59,24 @@ internal class MessageEncrypter @Inject constructor(private val credentials: Cre val ciphertext = HashMap() - for (deviceKey in participantKeys) { + for ((deviceKey, deviceInfo) in deviceInfoParticipantKey) { val sessionId = olmDevice.getSessionId(deviceKey) - if (!TextUtils.isEmpty(sessionId)) { + if (!sessionId.isNullOrEmpty()) { Timber.v("Using sessionid $sessionId for device $deviceKey") - val deviceInfo = deviceInfoParticipantKey[deviceKey] - payloadJson["recipient"] = deviceInfo!!.userId - - val recipientsKeysMap = HashMap() - recipientsKeysMap["ed25519"] = deviceInfo.fingerprint()!! - payloadJson["recipient_keys"] = recipientsKeysMap + payloadJson["recipient"] = deviceInfo.userId + payloadJson["recipient_keys"] = mapOf("ed25519" to deviceInfo.fingerprint()!!) val payloadString = convertToUTF8(JsonCanonicalizer.getCanonicalJson(Map::class.java, payloadJson)) - ciphertext[deviceKey] = olmDevice.encryptMessage(deviceKey, sessionId!!, payloadString!!)!! + ciphertext[deviceKey] = olmDevice.encryptMessage(deviceKey, sessionId, payloadString)!! } } - val res = EncryptedMessage() - - res.algorithm = MXCRYPTO_ALGORITHM_OLM - res.senderKey = olmDevice.deviceCurve25519Key - res.cipherText = ciphertext - - return res + return EncryptedMessage( + algorithm = MXCRYPTO_ALGORITHM_OLM, + senderKey = olmDevice.deviceCurve25519Key, + cipherText = ciphertext + ) } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/actions/SetDeviceVerificationAction.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/actions/SetDeviceVerificationAction.kt index 078d016e42..3eafa73fab 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/actions/SetDeviceVerificationAction.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/actions/SetDeviceVerificationAction.kt @@ -47,4 +47,4 @@ internal class SetDeviceVerificationAction @Inject constructor(private val crypt } } } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt index c518872d44..0230141e1b 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt @@ -17,7 +17,6 @@ package im.vector.matrix.android.internal.crypto.algorithms.megolm -import android.text.TextUtils import im.vector.matrix.android.api.session.crypto.MXCryptoError import im.vector.matrix.android.api.session.events.model.Event import im.vector.matrix.android.api.session.events.model.EventType @@ -129,7 +128,6 @@ internal class MXMegolmDecryption(private val userId: String, ) } - /** * Helper for the real decryptEvent and for _retryDecryption. If * requestKeysOnFail is true, we'll send an m.room_key_request when we fail @@ -149,7 +147,7 @@ internal class MXMegolmDecryption(private val userId: String, selfMap["deviceId"] = "*" recipients.add(selfMap) - if (!TextUtils.equals(sender, userId)) { + if (sender != userId) { val senderMap = HashMap() senderMap["userId"] = sender senderMap["deviceId"] = encryptedEventContent.deviceId!! @@ -177,18 +175,12 @@ internal class MXMegolmDecryption(private val userId: String, val encryptedEventContent = event.content.toModel() ?: return val pendingEventsKey = "${encryptedEventContent.senderKey}|${encryptedEventContent.sessionId}" + val timeline = pendingEvents.getOrPut(pendingEventsKey) { HashMap() } + val events = timeline.getOrPut(timelineId) { ArrayList() } - if (!pendingEvents.containsKey(pendingEventsKey)) { - pendingEvents[pendingEventsKey] = HashMap() - } - - if (pendingEvents[pendingEventsKey]?.containsKey(timelineId) == false) { - pendingEvents[pendingEventsKey]?.put(timelineId, ArrayList()) - } - - if (pendingEvents[pendingEventsKey]?.get(timelineId)?.contains(event) == false) { - Timber.v("## addEventToPendingList() : add Event " + event.eventId + " in room id " + event.roomId) - pendingEvents[pendingEventsKey]?.get(timelineId)?.add(event) + if (event !in events) { + Timber.v("## addEventToPendingList() : add Event ${event.eventId} in room id ${event.roomId}") + events.add(event) } } @@ -205,7 +197,7 @@ internal class MXMegolmDecryption(private val userId: String, var keysClaimed: MutableMap = HashMap() val forwardingCurve25519KeyChain: MutableList = ArrayList() - if (TextUtils.isEmpty(roomKeyContent.roomId) || TextUtils.isEmpty(roomKeyContent.sessionId) || TextUtils.isEmpty(roomKeyContent.sessionKey)) { + if (roomKeyContent.roomId.isNullOrEmpty() || roomKeyContent.sessionId.isNullOrEmpty() || roomKeyContent.sessionKey.isNullOrEmpty()) { Timber.e("## onRoomKeyEvent() : Key event is missing fields") return } @@ -252,13 +244,6 @@ internal class MXMegolmDecryption(private val userId: String, keysClaimed = event.getKeysClaimed().toMutableMap() } - if (roomKeyContent.sessionId == null - || roomKeyContent.sessionKey == null - || roomKeyContent.roomId == null) { - Timber.e("## invalid roomKeyContent") - return - } - val added = olmDevice.addInboundGroupSession(roomKeyContent.sessionId, roomKeyContent.sessionKey, roomKeyContent.roomId, @@ -352,4 +337,3 @@ internal class MXMegolmDecryption(private val userId: String, } } } - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/megolm/MXMegolmDecryptionFactory.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/megolm/MXMegolmDecryptionFactory.kt index 54c412526d..b7329221ab 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/megolm/MXMegolmDecryptionFactory.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/megolm/MXMegolmDecryptionFactory.kt @@ -49,4 +49,4 @@ internal class MXMegolmDecryptionFactory @Inject constructor(@UserId private val sendToDeviceTask, coroutineDispatchers) } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/megolm/MXMegolmEncryption.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/megolm/MXMegolmEncryption.kt index b465cb6e67..897a1f0a5d 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/megolm/MXMegolmEncryption.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/megolm/MXMegolmEncryption.kt @@ -18,7 +18,6 @@ package im.vector.matrix.android.internal.crypto.algorithms.megolm -import android.text.TextUtils import im.vector.matrix.android.api.auth.data.Credentials import im.vector.matrix.android.api.session.crypto.MXCryptoError import im.vector.matrix.android.api.session.events.model.Content @@ -38,7 +37,6 @@ import im.vector.matrix.android.internal.crypto.tasks.SendToDeviceTask import im.vector.matrix.android.internal.util.JsonCanonicalizer import im.vector.matrix.android.internal.util.convertToUTF8 import timber.log.Timber -import java.util.* internal class MXMegolmEncryption( // The id of the room we will be sending to. @@ -54,7 +52,6 @@ internal class MXMegolmEncryption( private val warnOnUnknownDevicesRepository: WarnOnUnknownDeviceRepository ) : IMXEncrypting { - // OutboundSessionInfo. Null if we haven't yet started setting one up. Note // that even if this is non-null, it may not be ready for use (in which // case outboundSession.shareOperation will be non-null.) @@ -86,7 +83,7 @@ internal class MXMegolmEncryption( keysClaimedMap["ed25519"] = olmDevice.deviceEd25519Key!! olmDevice.addInboundGroupSession(sessionId!!, olmDevice.getSessionKey(sessionId)!!, roomId, olmDevice.deviceCurve25519Key!!, - ArrayList(), keysClaimedMap, false) + emptyList(), keysClaimedMap, false) keysBackup.maybeBackupKeys() @@ -116,10 +113,8 @@ internal class MXMegolmEncryption( for (deviceId in deviceIds!!) { val deviceInfo = devicesInRoom.getObject(userId, deviceId) if (deviceInfo != null && null == safeSession.sharedWithDevices.getObject(userId, deviceId)) { - if (!shareMap.containsKey(userId)) { - shareMap[userId] = ArrayList() - } - shareMap[userId]!!.add(deviceInfo) + val devices = shareMap.getOrPut(userId) { ArrayList() } + devices.add(deviceInfo) } } } @@ -142,21 +137,17 @@ internal class MXMegolmEncryption( } // reduce the map size to avoid request timeout when there are too many devices (Users size * devices per user) val subMap = HashMap>() - val userIds = ArrayList() var devicesCount = 0 - for (userId in devicesByUsers.keys) { - devicesByUsers[userId]?.let { - userIds.add(userId) - subMap[userId] = it - devicesCount += it.size - } + for ((userId, devices) in devicesByUsers) { + subMap[userId] = devices + devicesCount += devices.size if (devicesCount > 100) { break } } - Timber.v("## shareKey() ; userId $userIds") + Timber.v("## shareKey() ; userId ${subMap.keys}") shareUserDevicesKey(session, subMap) - val remainingDevices = devicesByUsers.filterKeys { userIds.contains(it).not() } + val remainingDevices = devicesByUsers - subMap.keys shareKey(session, remainingDevices) } @@ -165,7 +156,6 @@ internal class MXMegolmEncryption( * * @param session the session info * @param devicesByUser the devices map - * @param callback the asynchronous callback */ private suspend fun shareUserDevicesKey(session: MXOutboundSessionInfo, devicesByUser: Map>) { @@ -211,8 +201,7 @@ internal class MXMegolmEncryption( continue } Timber.v("## shareUserDevicesKey() : Sharing keys with device $userId:$deviceID") - //noinspection ArraysAsListWithZeroOrOneArgument,ArraysAsListWithZeroOrOneArgument - contentMap.setObject(userId, deviceID, messageEncrypter.encryptMessage(payload, Arrays.asList(sessionResult.deviceInfo))) + contentMap.setObject(userId, deviceID, messageEncrypter.encryptMessage(payload, listOf(sessionResult.deviceInfo))) haveTargets = true } } @@ -229,9 +218,8 @@ internal class MXMegolmEncryption( // attempted to share with) rather than the contentMap (those we did // share with), because we don't want to try to claim a one-time-key // for dead devices on every message. - for (userId in devicesByUser.keys) { - val devicesToShareWith = devicesByUser[userId] - for ((deviceId) in devicesToShareWith!!) { + for ((userId, devicesToShareWith) in devicesByUser) { + for ((deviceId) in devicesToShareWith) { session.sharedWithDevices.setObject(userId, deviceId, chainIndex) } } @@ -253,7 +241,7 @@ internal class MXMegolmEncryption( // Get canonical Json from val payloadString = convertToUTF8(JsonCanonicalizer.getCanonicalJson(Map::class.java, payloadJson)) - val ciphertext = olmDevice.encryptGroupMessage(session.sessionId, payloadString!!) + val ciphertext = olmDevice.encryptGroupMessage(session.sessionId, payloadString) val map = HashMap() map["algorithm"] = MXCRYPTO_ALGORITHM_MEGOLM @@ -273,7 +261,6 @@ internal class MXMegolmEncryption( * This method must be called in getDecryptingThreadHandler() thread. * * @param userIds the user ids whose devices must be checked. - * @param callback the asynchronous callback */ private suspend fun getDevicesInRoom(userIds: List): MXUsersDevicesMap { // We are happy to use a cached version here: we assume that if we already @@ -305,7 +292,7 @@ internal class MXMegolmEncryption( continue } - if (TextUtils.equals(deviceInfo.identityKey(), olmDevice.deviceCurve25519Key)) { + if (deviceInfo.identityKey() == olmDevice.deviceCurve25519Key) { // Don't bother sending to ourself continue } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/megolm/MXMegolmEncryptionFactory.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/megolm/MXMegolmEncryptionFactory.kt index 682a3c11e3..dadd810a4b 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/megolm/MXMegolmEncryptionFactory.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/megolm/MXMegolmEncryptionFactory.kt @@ -51,4 +51,4 @@ internal class MXMegolmEncryptionFactory @Inject constructor( messageEncrypter, warnOnUnknownDevicesRepository) } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/olm/MXOlmDecryption.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/olm/MXOlmDecryption.kt index 9433e364cb..2f3b8a8f4a 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/olm/MXOlmDecryption.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/olm/MXOlmDecryption.kt @@ -63,6 +63,7 @@ internal class MXOlmDecryption( } // The message for myUser + @Suppress("UNCHECKED_CAST") val message = messageAny as JsonDict val decryptedPayload = decryptMessage(message, senderKey) @@ -72,10 +73,6 @@ internal class MXOlmDecryption( throw MXCryptoError.Base(MXCryptoError.ErrorType.BAD_ENCRYPTED_MESSAGE, MXCryptoError.BAD_ENCRYPTED_MESSAGE_REASON) } val payloadString = convertFromUTF8(decryptedPayload) - if (payloadString == null) { - Timber.e("## decryptEvent() Failed to decrypt Olm event (id= ${event.eventId} from $senderKey") - throw MXCryptoError.Base(MXCryptoError.ErrorType.BAD_ENCRYPTED_MESSAGE, MXCryptoError.BAD_ENCRYPTED_MESSAGE_REASON) - } val adapter = MoshiProvider.providesMoshi().adapter(JSON_DICT_PARAMETERIZED_TYPE) val payload = adapter.fromJson(payloadString) @@ -104,7 +101,8 @@ internal class MXOlmDecryption( } val recipientKeys = olmPayloadContent.recipient_keys ?: run { - Timber.e("## decryptEvent() : Olm event (id=${event.eventId}) contains no 'recipient_keys' property; cannot prevent unknown-key attack") + Timber.e("## decryptEvent() : Olm event (id=${event.eventId}) contains no 'recipient_keys'" + + " property; cannot prevent unknown-key attack") throw MXCryptoError.Base(MXCryptoError.ErrorType.MISSING_PROPERTY, String.format(MXCryptoError.ERROR_MISSING_PROPERTY_REASON, "recipient_keys")) } @@ -161,9 +159,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/im/vector/matrix/android/internal/crypto/algorithms/olm/MXOlmDecryptionFactory.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/olm/MXOlmDecryptionFactory.kt index 12937a2b2e..52a9a4f8c6 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/olm/MXOlmDecryptionFactory.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/olm/MXOlmDecryptionFactory.kt @@ -28,4 +28,4 @@ internal class MXOlmDecryptionFactory @Inject constructor(private val olmDevice: olmDevice, userId) } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/olm/MXOlmEncryption.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/olm/MXOlmEncryption.kt index 10d481dcfe..1c275940af 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/olm/MXOlmEncryption.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/olm/MXOlmEncryption.kt @@ -18,7 +18,6 @@ package im.vector.matrix.android.internal.crypto.algorithms.olm -import android.text.TextUtils import im.vector.matrix.android.api.session.events.model.Content import im.vector.matrix.android.api.session.events.model.toContent import im.vector.matrix.android.internal.crypto.DeviceListManager @@ -28,7 +27,6 @@ import im.vector.matrix.android.internal.crypto.actions.MessageEncrypter import im.vector.matrix.android.internal.crypto.algorithms.IMXEncrypting import im.vector.matrix.android.internal.crypto.model.MXDeviceInfo import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore -import java.util.* internal class MXOlmEncryption( private var roomId: String, @@ -49,7 +47,7 @@ internal class MXOlmEncryption( val devices = cryptoStore.getUserDevices(userId)?.values ?: emptyList() for (device in devices) { val key = device.identityKey() - if (TextUtils.equals(key, olmDevice.deviceCurve25519Key)) { + if (key == olmDevice.deviceCurve25519Key) { // Don't bother setting up session to ourself continue } @@ -61,16 +59,16 @@ internal class MXOlmEncryption( } } - val messageMap = HashMap() - messageMap["room_id"] = roomId - messageMap["type"] = eventType - messageMap["content"] = eventContent + val messageMap = mapOf( + "room_id" to roomId, + "type" to eventType, + "content" to eventContent + ) messageEncrypter.encryptMessage(messageMap, deviceInfos) - return messageMap.toContent()!! + return messageMap.toContent() } - /** * Ensure that the session * diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/olm/MXOlmEncryptionFactory.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/olm/MXOlmEncryptionFactory.kt index eff833cf21..ef4057fe26 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/olm/MXOlmEncryptionFactory.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/olm/MXOlmEncryptionFactory.kt @@ -40,4 +40,4 @@ internal class MXOlmEncryptionFactory @Inject constructor(private val olmDevice: deviceListManager, ensureOlmSessionsForUsersAction) } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/api/CryptoApi.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/api/CryptoApi.kt index 263cfef2f8..f4821f8ef3 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/api/CryptoApi.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/api/CryptoApi.kt @@ -16,7 +16,6 @@ */ package im.vector.matrix.android.internal.crypto.api - import im.vector.matrix.android.internal.crypto.model.rest.* import im.vector.matrix.android.internal.network.NetworkConstants import retrofit2.Call diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/attachments/ElementToDecrypt.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/attachments/ElementToDecrypt.kt index 3bd29ae262..a3fc98f674 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/attachments/ElementToDecrypt.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/attachments/ElementToDecrypt.kt @@ -20,7 +20,6 @@ import android.os.Parcelable import im.vector.matrix.android.internal.crypto.model.rest.EncryptedFileInfo import kotlinx.android.parcel.Parcelize - fun EncryptedFileInfo.toElementToDecrypt(): ElementToDecrypt? { // Check the validity of some fields if (isValid()) { @@ -35,7 +34,6 @@ fun EncryptedFileInfo.toElementToDecrypt(): ElementToDecrypt? { return null } - /** * Represent data to decode an attachment */ @@ -44,4 +42,4 @@ data class ElementToDecrypt( val iv: String, val k: String, val sha256: String -) : Parcelable \ No newline at end of file +) : Parcelable diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/attachments/MXEncryptedAttachments.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/attachments/MXEncryptedAttachments.kt index c699325562..5f90b636ac 100755 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/attachments/MXEncryptedAttachments.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/attachments/MXEncryptedAttachments.kt @@ -17,7 +17,6 @@ package im.vector.matrix.android.internal.crypto.attachments import android.util.Base64 -import arrow.core.Try import im.vector.matrix.android.internal.crypto.model.rest.EncryptedFileInfo import im.vector.matrix.android.internal.crypto.model.rest.EncryptedFileKey import timber.log.Timber @@ -50,7 +49,7 @@ object MXEncryptedAttachments { * @param mimetype the mime type * @return the encryption file info */ - fun encryptAttachment(attachmentStream: InputStream, mimetype: String): Try { + fun encryptAttachment(attachmentStream: InputStream, mimetype: String): EncryptionResult { val t0 = System.currentTimeMillis() val secureRandom = SecureRandom() @@ -70,7 +69,7 @@ object MXEncryptedAttachments { val outStream = ByteArrayOutputStream() - try { + outStream.use { val encryptCipher = Cipher.getInstance(CIPHER_ALGORITHM) val secretKeySpec = SecretKeySpec(key, SECRET_KEY_SPEC_ALGORITHM) val ivParameterSpec = IvParameterSpec(initVectorBytes) @@ -104,29 +103,17 @@ object MXEncryptedAttachments { ext = true, key_ops = listOf("encrypt", "decrypt"), kty = "oct", - k = base64ToBase64Url(Base64.encodeToString(key, Base64.DEFAULT))!! + k = base64ToBase64Url(Base64.encodeToString(key, Base64.DEFAULT)) ), iv = Base64.encodeToString(initVectorBytes, Base64.DEFAULT).replace("\n", "").replace("=", ""), - hashes = mapOf("sha256" to base64ToUnpaddedBase64(Base64.encodeToString(messageDigest.digest(), Base64.DEFAULT))!!), + hashes = mapOf("sha256" to base64ToUnpaddedBase64(Base64.encodeToString(messageDigest.digest(), Base64.DEFAULT))), v = "v2" ), encryptedByteArray = outStream.toByteArray() ) Timber.v("Encrypt in ${System.currentTimeMillis() - t0} ms") - return Try.just(result) - } catch (oom: OutOfMemoryError) { - Timber.e(oom, "## encryptAttachment failed") - return Try.Failure(oom) - } catch (e: Exception) { - Timber.e(e, "## encryptAttachment failed") - return Try.Failure(e) - } finally { - try { - outStream.close() - } catch (e: Exception) { - Timber.e(e, "## encryptAttachment() : fail to close outStream") - } + return result } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/KeysBackup.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/KeysBackup.kt index 786923dad5..b3ee138591 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/KeysBackup.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/KeysBackup.kt @@ -21,7 +21,6 @@ import android.os.Looper import androidx.annotation.UiThread import androidx.annotation.VisibleForTesting import androidx.annotation.WorkerThread -import arrow.core.Try import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.auth.data.Credentials import im.vector.matrix.android.api.failure.Failure @@ -31,6 +30,7 @@ import im.vector.matrix.android.api.listeners.StepProgressListener import im.vector.matrix.android.api.session.crypto.keysbackup.KeysBackupService import im.vector.matrix.android.api.session.crypto.keysbackup.KeysBackupState import im.vector.matrix.android.api.session.crypto.keysbackup.KeysBackupStateListener +import im.vector.matrix.android.api.util.JsonDict import im.vector.matrix.android.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM_BACKUP import im.vector.matrix.android.internal.crypto.MXOlmDevice import im.vector.matrix.android.internal.crypto.MegolmSessionData @@ -49,6 +49,7 @@ import im.vector.matrix.android.internal.crypto.model.OlmInboundGroupSessionWrap import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore import im.vector.matrix.android.internal.crypto.store.db.model.KeysBackupDataEntity import im.vector.matrix.android.internal.di.MoshiProvider +import im.vector.matrix.android.internal.di.UserId import im.vector.matrix.android.internal.extensions.foldToCallback import im.vector.matrix.android.internal.session.SessionScope import im.vector.matrix.android.internal.task.Task @@ -57,6 +58,7 @@ import im.vector.matrix.android.internal.task.TaskThread import im.vector.matrix.android.internal.task.configureWith import im.vector.matrix.android.internal.util.JsonCanonicalizer import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers +import im.vector.matrix.android.internal.util.awaitCallback import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -76,6 +78,7 @@ import kotlin.random.Random @SessionScope internal class KeysBackup @Inject constructor( + @UserId private val userId: String, private val credentials: Credentials, private val cryptoStore: IMXCryptoStore, private val olmDevice: MXOlmDevice, @@ -141,8 +144,8 @@ internal class KeysBackup @Inject constructor( progressListener: ProgressListener?, callback: MatrixCallback) { GlobalScope.launch(coroutineDispatchers.main) { - withContext(coroutineDispatchers.crypto) { - Try { + runCatching { + withContext(coroutineDispatchers.crypto) { val olmPkDecryption = OlmPkDecryption() val megolmBackupAuthData = MegolmBackupAuthData() @@ -178,7 +181,6 @@ internal class KeysBackup @Inject constructor( megolmBackupAuthData.signatures = objectSigner.signObject(canonicalJson) - val megolmBackupCreationInfo = MegolmBackupCreationInfo() megolmBackupCreationInfo.algorithm = MXCRYPTO_ALGORITHM_MEGOLM_BACKUP megolmBackupCreationInfo.authData = megolmBackupAuthData @@ -194,22 +196,23 @@ internal class KeysBackup @Inject constructor( callback: MatrixCallback) { val createKeysBackupVersionBody = CreateKeysBackupVersionBody() createKeysBackupVersionBody.algorithm = keysBackupCreationInfo.algorithm + @Suppress("UNCHECKED_CAST") createKeysBackupVersionBody.authData = MoshiProvider.providesMoshi().adapter(Map::class.java) - .fromJson(keysBackupCreationInfo.authData?.toJsonString()) as Map? + .fromJson(keysBackupCreationInfo.authData?.toJsonString() ?: "") as JsonDict? keysBackupStateManager.state = KeysBackupState.Enabling createKeysBackupVersionTask .configureWith(createKeysBackupVersionBody) { this.callback = object : MatrixCallback { - override fun onSuccess(info: KeysVersion) { + override fun onSuccess(data: KeysVersion) { // Reset backup markers. cryptoStore.resetBackupMarkers() val keyBackupVersion = KeysVersionResult() keyBackupVersion.algorithm = createKeysBackupVersionBody.algorithm keyBackupVersion.authData = createKeysBackupVersionBody.authData - keyBackupVersion.version = info.version + keyBackupVersion.version = data.version // We can consider that the server does not have keys yet keyBackupVersion.count = 0 @@ -217,7 +220,7 @@ internal class KeysBackup @Inject constructor( enableKeysBackup(keyBackupVersion) - callback.onSuccess(info) + callback.onSuccess(data) } override fun onFailure(failure: Throwable) { @@ -275,7 +278,8 @@ internal class KeysBackup @Inject constructor( val keysBackupData = cryptoStore.getKeysBackupData() val totalNumberOfKeysServer = keysBackupData?.backupLastServerNumberOfKeys ?: -1 - val hashServer = keysBackupData?.backupLastServerHash + // Not used for the moment + // val hashServer = keysBackupData?.backupLastServerHash return when { totalNumberOfKeysLocally < totalNumberOfKeysServer -> { @@ -293,7 +297,6 @@ internal class KeysBackup @Inject constructor( override fun getTotalNumbersOfKeys(): Int { return cryptoStore.inboundGroupSessionsCount(false) - } override fun getTotalNumbersOfBackedUpKeys(): Int { @@ -374,8 +377,6 @@ internal class KeysBackup @Inject constructor( */ @WorkerThread private fun getKeysBackupTrustBg(keysBackupVersion: KeysVersionResult): KeysBackupVersionTrust { - val myUserId = credentials.userId - val keysBackupVersionTrust = KeysBackupVersionTrust() val authData = keysBackupVersion.getAuthDataAsMegolmBackupAuthData() @@ -387,13 +388,13 @@ internal class KeysBackup @Inject constructor( return keysBackupVersionTrust } - val mySigs = authData.signatures?.get(myUserId) + val mySigs = authData.signatures?.get(userId) if (mySigs.isNullOrEmpty()) { Timber.v("getKeysBackupTrust: Ignoring key backup because it lacks any signatures from this user") return keysBackupVersionTrust } - for (keyId in mySigs.keys) { + for ((keyId, mySignature) in mySigs) { // XXX: is this how we're supposed to get the device id? var deviceId: String? = null val components = keyId.split(":") @@ -402,7 +403,7 @@ internal class KeysBackup @Inject constructor( } if (deviceId != null) { - val device = cryptoStore.getUserDevice(deviceId, myUserId) + val device = cryptoStore.getUserDevice(deviceId, userId) var isSignatureValid = false if (device == null) { @@ -411,10 +412,10 @@ internal class KeysBackup @Inject constructor( val fingerprint = device.fingerprint() if (fingerprint != null) { try { - olmDevice.verifySignature(fingerprint, authData.signalableJSONDictionary(), mySigs[keyId] as String) + olmDevice.verifySignature(fingerprint, authData.signalableJSONDictionary(), mySignature) isSignatureValid = true } catch (e: OlmException) { - Timber.v("getKeysBackupTrust: Bad signature from device " + device.deviceId + " " + e.localizedMessage) + Timber.v(e, "getKeysBackupTrust: Bad signature from device ${device.deviceId}") } } @@ -449,10 +450,8 @@ internal class KeysBackup @Inject constructor( } else { GlobalScope.launch(coroutineDispatchers.main) { val updateKeysBackupVersionBody = withContext(coroutineDispatchers.crypto) { - val myUserId = credentials.userId - // Get current signatures, or create an empty set - val myUserSignatures = authData.signatures?.get(myUserId)?.toMutableMap() + val myUserSignatures = authData.signatures?.get(userId)?.toMutableMap() ?: HashMap() if (trust) { @@ -461,7 +460,7 @@ internal class KeysBackup @Inject constructor( val deviceSignatures = objectSigner.signObject(canonicalJson) - deviceSignatures[myUserId]?.forEach { entry -> + deviceSignatures[userId]?.forEach { entry -> myUserSignatures[entry.key] = entry.value } } else { @@ -477,13 +476,14 @@ internal class KeysBackup @Inject constructor( val newMegolmBackupAuthData = authData.copy() val newSignatures = newMegolmBackupAuthData.signatures!!.toMutableMap() - newSignatures[myUserId] = myUserSignatures + newSignatures[userId] = myUserSignatures newMegolmBackupAuthData.signatures = newSignatures val moshi = MoshiProvider.providesMoshi() val adapter = moshi.adapter(Map::class.java) + @Suppress("UNCHECKED_CAST") updateKeysBackupVersionBody.authData = adapter.fromJson(newMegolmBackupAuthData.toJsonString()) as Map? updateKeysBackupVersionBody @@ -615,8 +615,8 @@ internal class KeysBackup @Inject constructor( Timber.v("restoreKeysWithRecoveryKey: From backup version: ${keysVersionResult.version}") GlobalScope.launch(coroutineDispatchers.main) { - withContext(coroutineDispatchers.crypto) { - Try { + runCatching { + val decryption = withContext(coroutineDispatchers.crypto) { // Check if the recovery is valid before going any further if (!isValidRecoveryKeyForKeysBackupVersion(recoveryKey, keysVersionResult)) { Timber.e("restoreKeysWithRecoveryKey: Invalid recovery key for this keys version") @@ -624,85 +624,66 @@ internal class KeysBackup @Inject constructor( } // Get a PK decryption instance - val decryption = pkDecryptionFromRecoveryKey(recoveryKey) - if (decryption == null) { - // This should not happen anymore - Timber.e("restoreKeysWithRecoveryKey: Invalid recovery key. Error") - throw InvalidParameterException("Invalid recovery key") - } - - decryption!! + pkDecryptionFromRecoveryKey(recoveryKey) + } + if (decryption == null) { + // This should not happen anymore + Timber.e("restoreKeysWithRecoveryKey: Invalid recovery key. Error") + throw InvalidParameterException("Invalid recovery key") } - }.fold( - { - callback.onFailure(it) - }, - { decryption -> - stepProgressListener?.onStepProgress(StepProgressListener.Step.DownloadingKey) - // Get backed up keys from the homeserver - getKeys(sessionId, roomId, keysVersionResult.version!!, object : MatrixCallback { - override fun onSuccess(data: KeysBackupData) { - GlobalScope.launch(coroutineDispatchers.main) { - val importRoomKeysResult = withContext(coroutineDispatchers.crypto) { - val sessionsData = ArrayList() - // Restore that data - var sessionsFromHsCount = 0 - for (roomIdLoop in data.roomIdToRoomKeysBackupData.keys) { - for (sessionIdLoop in data.roomIdToRoomKeysBackupData[roomIdLoop]!!.sessionIdToKeyBackupData.keys) { - sessionsFromHsCount++ + stepProgressListener?.onStepProgress(StepProgressListener.Step.DownloadingKey) - val keyBackupData = data.roomIdToRoomKeysBackupData[roomIdLoop]!!.sessionIdToKeyBackupData[sessionIdLoop]!! + // Get backed up keys from the homeserver + val data = getKeys(sessionId, roomId, keysVersionResult.version!!) - val sessionData = decryptKeyBackupData(keyBackupData, sessionIdLoop, roomIdLoop, decryption) + withContext(coroutineDispatchers.crypto) { + val sessionsData = ArrayList() + // Restore that data + var sessionsFromHsCount = 0 + for ((roomIdLoop, backupData) in data.roomIdToRoomKeysBackupData) { + for ((sessionIdLoop, keyBackupData) in backupData.sessionIdToKeyBackupData) { + sessionsFromHsCount++ - sessionData?.let { - sessionsData.add(it) - } - } - } - Timber.v("restoreKeysWithRecoveryKey: Decrypted " + sessionsData.size + " keys out of " - + sessionsFromHsCount + " from the backup store on the homeserver") + val sessionData = decryptKeyBackupData(keyBackupData, sessionIdLoop, roomIdLoop, decryption) - // Do not trigger a backup for them if they come from the backup version we are using - val backUp = keysVersionResult.version != keysBackupVersion?.version - if (backUp) { - Timber.v("restoreKeysWithRecoveryKey: Those keys will be backed up to backup version: " - + keysBackupVersion?.version) - } - - // Import them into the crypto store - val progressListener = if (stepProgressListener != null) { - object : ProgressListener { - override fun onProgress(progress: Int, total: Int) { - // Note: no need to post to UI thread, importMegolmSessionsData() will do it - stepProgressListener.onStepProgress(StepProgressListener.Step.ImportingKey(progress, total)) - } - } - } else { - null - } - - val result = megolmSessionDataImporter.handle(sessionsData, !backUp, uiHandler, progressListener) - - // Do not back up the key if it comes from a backup recovery - if (backUp) { - maybeBackupKeys() - } - - result - } - - callback.onSuccess(importRoomKeysResult) - } + sessionData?.let { + sessionsData.add(it) } - - override fun onFailure(failure: Throwable) { - callback.onFailure(failure) - } - }) + } } - ) + Timber.v("restoreKeysWithRecoveryKey: Decrypted ${sessionsData.size} keys out" + + " of $sessionsFromHsCount from the backup store on the homeserver") + + // Do not trigger a backup for them if they come from the backup version we are using + val backUp = keysVersionResult.version != keysBackupVersion?.version + if (backUp) { + Timber.v("restoreKeysWithRecoveryKey: Those keys will be backed up" + + " to backup version: ${keysBackupVersion?.version}") + } + + // Import them into the crypto store + val progressListener = if (stepProgressListener != null) { + object : ProgressListener { + override fun onProgress(progress: Int, total: Int) { + // Note: no need to post to UI thread, importMegolmSessionsData() will do it + stepProgressListener.onStepProgress(StepProgressListener.Step.ImportingKey(progress, total)) + } + } + } else { + null + } + + val result = megolmSessionDataImporter.handle(sessionsData, !backUp, uiHandler, progressListener) + + // Do not back up the key if it comes from a backup recovery + if (backUp) { + maybeBackupKeys() + } + + result + } + }.foldToCallback(callback) } } @@ -715,7 +696,7 @@ internal class KeysBackup @Inject constructor( Timber.v("[MXKeyBackup] restoreKeyBackup with password: From backup version: ${keysBackupVersion.version}") GlobalScope.launch(coroutineDispatchers.main) { - withContext(coroutineDispatchers.crypto) { + runCatching { val progressListener = if (stepProgressListener != null) { object : ProgressListener { override fun onProgress(progress: Int, total: Int) { @@ -728,22 +709,18 @@ internal class KeysBackup @Inject constructor( null } - Try { + val recoveryKey = withContext(coroutineDispatchers.crypto) { recoveryKeyFromPassword(password, keysBackupVersion, progressListener) } - }.fold( - { - callback.onFailure(it) - }, - { recoveryKey -> - if (recoveryKey == null) { - Timber.v("backupKeys: Invalid configuration") - callback.onFailure(IllegalStateException("Invalid configuration")) - } else { - restoreKeysWithRecoveryKey(keysBackupVersion, recoveryKey, roomId, sessionId, stepProgressListener, callback) - } + if (recoveryKey == null) { + Timber.v("backupKeys: Invalid configuration") + throw IllegalStateException("Invalid configuration") + } else { + awaitCallback { + restoreKeysWithRecoveryKey(keysBackupVersion, recoveryKey, roomId, sessionId, stepProgressListener, it) } - ) + } + }.foldToCallback(callback) } } @@ -751,60 +728,26 @@ internal class KeysBackup @Inject constructor( * Same method as [RoomKeysRestClient.getRoomKey] except that it accepts nullable * parameters and always returns a KeysBackupData object through the Callback */ - private fun getKeys(sessionId: String?, + private suspend fun getKeys(sessionId: String?, roomId: String?, - version: String, - callback: MatrixCallback) { - if (roomId != null && sessionId != null) { + version: String): KeysBackupData { + return if (roomId != null && sessionId != null) { // Get key for the room and for the session - getRoomSessionDataTask - .configureWith(GetRoomSessionDataTask.Params(roomId, sessionId, version)) { - this.callback = object : MatrixCallback { - override fun onSuccess(data: KeyBackupData) { - // Convert to KeysBackupData - val keysBackupData = KeysBackupData() - keysBackupData.roomIdToRoomKeysBackupData = HashMap() - val roomKeysBackupData = RoomKeysBackupData() - roomKeysBackupData.sessionIdToKeyBackupData = HashMap() - roomKeysBackupData.sessionIdToKeyBackupData[sessionId] = data - keysBackupData.roomIdToRoomKeysBackupData[roomId] = roomKeysBackupData - - callback.onSuccess(keysBackupData) - } - - override fun onFailure(failure: Throwable) { - callback.onFailure(failure) - } - } - } - .executeBy(taskExecutor) + val data = getRoomSessionDataTask.execute(GetRoomSessionDataTask.Params(roomId, sessionId, version)) + // Convert to KeysBackupData + KeysBackupData(mutableMapOf( + roomId to RoomKeysBackupData(mutableMapOf( + sessionId to data + )) + )) } else if (roomId != null) { // Get all keys for the room - getRoomSessionsDataTask - .configureWith(GetRoomSessionsDataTask.Params(roomId, version)) { - this.callback = object : MatrixCallback { - override fun onSuccess(data: RoomKeysBackupData) { - // Convert to KeysBackupData - val keysBackupData = KeysBackupData() - keysBackupData.roomIdToRoomKeysBackupData = HashMap() - keysBackupData.roomIdToRoomKeysBackupData[roomId] = data - - callback.onSuccess(keysBackupData) - } - - override fun onFailure(failure: Throwable) { - callback.onFailure(failure) - } - } - } - .executeBy(taskExecutor) + val data = getRoomSessionsDataTask.execute(GetRoomSessionsDataTask.Params(roomId, version)) + // Convert to KeysBackupData + KeysBackupData(mutableMapOf(roomId to data)) } else { // Get all keys - getSessionsDataTask - .configureWith(GetSessionsDataTask.Params(version)) { - this.callback = callback - } - .executeBy(taskExecutor) + getSessionsDataTask.execute(GetSessionsDataTask.Params(version)) } } @@ -823,7 +766,6 @@ internal class KeysBackup @Inject constructor( } catch (e: OlmException) { Timber.e(e, "OlmException") } - } return decryption @@ -981,12 +923,11 @@ internal class KeysBackup @Inject constructor( keysBackupStateManager.state = KeysBackupState.Disabled } else { getKeysBackupTrust(keyBackupVersion, object : MatrixCallback { - override fun onSuccess(data: KeysBackupVersionTrust) { val versionInStore = cryptoStore.getKeyBackupVersion() if (data.usable) { - Timber.v("checkAndStartWithKeysBackupVersion: Found usable key backup. version: " + keyBackupVersion.version) + Timber.v("checkAndStartWithKeysBackupVersion: Found usable key backup. version: ${keyBackupVersion.version}") // Check the version we used at the previous app run if (versionInStore != null && versionInStore != keyBackupVersion.version) { Timber.v(" -> clean the previously used version $versionInStore") @@ -996,7 +937,7 @@ internal class KeysBackup @Inject constructor( Timber.v(" -> enabling key backups") enableKeysBackup(keyBackupVersion) } else { - Timber.v("checkAndStartWithKeysBackupVersion: No usable key backup. version: " + keyBackupVersion.version) + Timber.v("checkAndStartWithKeysBackupVersion: No usable key backup. version: ${keyBackupVersion.version}") if (versionInStore != null) { Timber.v(" -> disabling key backup") resetKeysBackupData() @@ -1009,7 +950,6 @@ internal class KeysBackup @Inject constructor( override fun onFailure(failure: Throwable) { // Cannot happen } - }) } } @@ -1201,7 +1141,7 @@ internal class KeysBackup @Inject constructor( // Get a chunk of keys to backup val olmInboundGroupSessionWrappers = cryptoStore.inboundGroupSessionsToBackup(KEY_BACKUP_SEND_KEYS_MAX_COUNT) - Timber.v("backupKeys: 1 - " + olmInboundGroupSessionWrappers.size + " sessions to back up") + Timber.v("backupKeys: 1 - ${olmInboundGroupSessionWrappers.size} sessions to back up") if (olmInboundGroupSessionWrappers.isEmpty()) { // Backup is up to date @@ -1412,5 +1352,5 @@ internal class KeysBackup @Inject constructor( * DEBUG INFO * ========================================================================================== */ - override fun toString() = "KeysBackup for ${credentials.userId}" + override fun toString() = "KeysBackup for $userId" } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/KeysBackupPassword.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/KeysBackupPassword.kt index eabd5dff04..344ba61277 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/KeysBackupPassword.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/KeysBackupPassword.kt @@ -27,7 +27,6 @@ import javax.crypto.Mac import javax.crypto.spec.SecretKeySpec import kotlin.experimental.xor - private const val SALT_LENGTH = 32 private const val DEFAULT_ITERATION = 500_000 @@ -133,7 +132,7 @@ private fun deriveKey(password: String, } } - Timber.v("KeysBackupPassword", "## deriveKeys() : " + iterations + " in " + (System.currentTimeMillis() - t0) + " ms") + Timber.v("KeysBackupPassword: deriveKeys() : " + iterations + " in " + (System.currentTimeMillis() - t0) + " ms") return dk } @@ -149,4 +148,4 @@ private fun generateSalt(): String { } return salt.substring(0, SALT_LENGTH) -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/api/RoomKeysApi.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/api/RoomKeysApi.kt index 73b6112fd8..f5d89fb5eb 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/api/RoomKeysApi.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/api/RoomKeysApi.kt @@ -142,7 +142,6 @@ internal interface RoomKeysApi { @GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "room_keys/keys") fun getSessionsData(@Query("version") version: String): Call - /* ========================================================================================== * Deleting keys * ========================================================================================== */ diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/model/KeyBackupVersionTrustSignature.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/model/KeyBackupVersionTrustSignature.kt index fce77b33e5..caf4aaad0b 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/model/KeyBackupVersionTrustSignature.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/model/KeyBackupVersionTrustSignature.kt @@ -32,5 +32,4 @@ class KeyBackupVersionTrustSignature { *Flag to indicate the signature from this device is valid. */ var valid = false - } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/model/KeysBackupVersionTrust.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/model/KeysBackupVersionTrust.kt index ed765d1449..fc642b3fb2 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/model/KeysBackupVersionTrust.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/model/KeysBackupVersionTrust.kt @@ -30,4 +30,4 @@ data class KeysBackupVersionTrust( * Signatures found in the backup version. */ var signatures: MutableList = ArrayList() -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/model/KeysBackupVersionTrustSignature.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/model/KeysBackupVersionTrustSignature.kt index afa6b77921..d91189a4bf 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/model/KeysBackupVersionTrustSignature.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/model/KeysBackupVersionTrustSignature.kt @@ -38,5 +38,4 @@ class KeysBackupVersionTrustSignature { * Flag to indicate the signature from this device is valid. */ var valid = false - } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/model/MegolmBackupCreationInfo.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/model/MegolmBackupCreationInfo.kt index 2be7806b86..a08ba9ba96 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/model/MegolmBackupCreationInfo.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/model/MegolmBackupCreationInfo.kt @@ -35,5 +35,4 @@ class MegolmBackupCreationInfo { * The Base58 recovery key. */ var recoveryKey: String = "" - } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/model/rest/KeysAlgorithmAndData.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/model/rest/KeysAlgorithmAndData.kt index 20e7357a39..6fba833589 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/model/rest/KeysAlgorithmAndData.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/model/rest/KeysAlgorithmAndData.kt @@ -17,6 +17,7 @@ package im.vector.matrix.android.internal.crypto.keysbackup.model.rest import com.squareup.moshi.Json +import im.vector.matrix.android.api.util.JsonDict import im.vector.matrix.android.internal.crypto.keysbackup.model.MegolmBackupAuthData import im.vector.matrix.android.internal.di.MoshiProvider @@ -49,7 +50,7 @@ open class KeysAlgorithmAndData { * algorithm-dependent data, for "m.megolm_backup.v1.curve25519-aes-sha2" see [im.vector.matrix.android.internal.crypto.keysbackup.MegolmBackupAuthData] */ @Json(name = "auth_data") - var authData: Map? = null + var authData: JsonDict? = null /** * Facility method to convert authData to a MegolmBackupAuthData object diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/model/rest/KeysVersionResult.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/model/rest/KeysVersionResult.kt index bff8f13894..4510cdd773 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/model/rest/KeysVersionResult.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/model/rest/KeysVersionResult.kt @@ -28,4 +28,4 @@ data class KeysVersionResult( // The number of keys stored in the backup. var count: Int? = null -) : KeysAlgorithmAndData() \ No newline at end of file +) : KeysAlgorithmAndData() diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/model/rest/UpdateKeysBackupVersionBody.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/model/rest/UpdateKeysBackupVersionBody.kt index e2d628c459..cb8ba5e26c 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/model/rest/UpdateKeysBackupVersionBody.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/model/rest/UpdateKeysBackupVersionBody.kt @@ -22,4 +22,4 @@ import com.squareup.moshi.JsonClass data class UpdateKeysBackupVersionBody( // the backup version, mandatory val version: String -) : KeysAlgorithmAndData() \ No newline at end of file +) : KeysAlgorithmAndData() diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/tasks/CreateKeysBackupVersionTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/tasks/CreateKeysBackupVersionTask.kt index 5aaaaea5b3..78ae0f7ea6 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/tasks/CreateKeysBackupVersionTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/tasks/CreateKeysBackupVersionTask.kt @@ -28,7 +28,6 @@ internal interface CreateKeysBackupVersionTask : Task { data class Params( val version: String diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/tasks/GetKeysBackupLastVersionTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/tasks/GetKeysBackupLastVersionTask.kt index 3007622690..874a1749d6 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/tasks/GetKeysBackupLastVersionTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/tasks/GetKeysBackupLastVersionTask.kt @@ -27,7 +27,6 @@ internal interface GetKeysBackupLastVersionTask : Task internal class DefaultGetKeysBackupLastVersionTask @Inject constructor(private val roomKeysApi: RoomKeysApi) : GetKeysBackupLastVersionTask { - override suspend fun execute(params: Unit): KeysVersionResult { return executeRequest { apiCall = roomKeysApi.getKeysBackupLastVersion() diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/tasks/GetKeysBackupVersionTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/tasks/GetKeysBackupVersionTask.kt index c36f039c3c..ea0b9b9f3a 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/tasks/GetKeysBackupVersionTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/tasks/GetKeysBackupVersionTask.kt @@ -27,7 +27,6 @@ internal interface GetKeysBackupVersionTask : Task internal class DefaultGetKeysBackupVersionTask @Inject constructor(private val roomKeysApi: RoomKeysApi) : GetKeysBackupVersionTask { - override suspend fun execute(params: String): KeysVersionResult { return executeRequest { apiCall = roomKeysApi.getKeysBackupVersion(params) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/tasks/GetRoomSessionsDataTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/tasks/GetRoomSessionsDataTask.kt index e8888f2590..ba903de8c1 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/tasks/GetRoomSessionsDataTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/tasks/GetRoomSessionsDataTask.kt @@ -22,7 +22,6 @@ import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.task.Task import javax.inject.Inject - internal interface GetRoomSessionsDataTask : Task { data class Params( val roomId: String, diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/tasks/UpdateKeysBackupVersionTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/tasks/UpdateKeysBackupVersionTask.kt index 28aedaf800..30b60af418 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/tasks/UpdateKeysBackupVersionTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/tasks/UpdateKeysBackupVersionTask.kt @@ -32,7 +32,6 @@ internal interface UpdateKeysBackupVersionTask : Task? = null -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/MXUsersDevicesMap.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/MXUsersDevicesMap.kt index 348b6ade12..bbad25ef51 100755 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/MXUsersDevicesMap.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/MXUsersDevicesMap.kt @@ -16,7 +16,6 @@ package im.vector.matrix.android.internal.crypto.model - class MXUsersDevicesMap { // A map of maps (userId -> (deviceId -> Object)). @@ -119,4 +118,4 @@ class MXUsersDevicesMap { override fun toString(): String { return "MXUsersDevicesMap $map" } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/OlmInboundGroupSessionWrapper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/OlmInboundGroupSessionWrapper.kt index 646f6b9c5b..361b8bc205 100755 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/OlmInboundGroupSessionWrapper.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/OlmInboundGroupSessionWrapper.kt @@ -17,13 +17,11 @@ package im.vector.matrix.android.internal.crypto.model -import android.text.TextUtils import im.vector.matrix.android.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM import im.vector.matrix.android.internal.crypto.MegolmSessionData import org.matrix.olm.OlmInboundGroupSession import timber.log.Timber import java.io.Serializable -import java.util.* /** * This class adds more context to a OlmInboundGroupSession object. @@ -57,7 +55,6 @@ class OlmInboundGroupSessionWrapper : Serializable { } catch (e: Exception) { Timber.e(e, "## getFirstKnownIndex() : getFirstKnownIndex failed") } - } return null @@ -79,7 +76,6 @@ class OlmInboundGroupSessionWrapper : Serializable { } catch (e: Exception) { Timber.e(e, "Cannot create") } - } /** @@ -93,7 +89,7 @@ class OlmInboundGroupSessionWrapper : Serializable { try { olmInboundGroupSession = OlmInboundGroupSession.importSession(megolmSessionData.sessionKey!!) - if (!TextUtils.equals(olmInboundGroupSession!!.sessionIdentifier(), megolmSessionData.sessionId)) { + if (olmInboundGroupSession!!.sessionIdentifier() != megolmSessionData.sessionId) { throw Exception("Mismatched group session Id") } @@ -149,9 +145,8 @@ class OlmInboundGroupSessionWrapper : Serializable { } catch (e: Exception) { Timber.e(e, "## exportSession() : export failed") } - } return null } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/OlmSessionWrapper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/OlmSessionWrapper.kt index a413abd5d8..acd056d9b9 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/OlmSessionWrapper.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/OlmSessionWrapper.kt @@ -33,4 +33,4 @@ data class OlmSessionWrapper( fun onMessageReceived() { lastReceivedMessageTs = System.currentTimeMillis() } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/event/EncryptedEventContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/event/EncryptedEventContent.kt index 4d06b737e8..3efb2f59ad 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/event/EncryptedEventContent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/event/EncryptedEventContent.kt @@ -55,6 +55,6 @@ data class EncryptedEventContent( @Json(name = "session_id") val sessionId: String? = null, - //Relation context is in clear in encrypted message + // Relation context is in clear in encrypted message @Json(name = "m.relates_to") val relatesTo: RelationDefaultContent? = null -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/event/EncryptionEventContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/event/EncryptionEventContent.kt index 22df41e903..6de50f84c2 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/event/EncryptionEventContent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/event/EncryptionEventContent.kt @@ -41,4 +41,4 @@ data class EncryptionEventContent( */ @Json(name = "rotation_period_msgs") var rotationPeriodMsgs: Long? = null -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/event/OlmPayloadContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/event/OlmPayloadContent.kt index c33ddb41a9..bf5833a44f 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/event/OlmPayloadContent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/event/OlmPayloadContent.kt @@ -58,5 +58,3 @@ data class OlmPayloadContent( } } } - - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/DeviceInfo.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/DeviceInfo.kt index 1bd5f671cc..1289ef3d92 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/DeviceInfo.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/DeviceInfo.kt @@ -59,5 +59,4 @@ data class DeviceInfo( override val date: Long get() = lastSeenTs ?: 0 - } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/EncryptedFileKey.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/EncryptedFileKey.kt index 3cf1e3083a..799819ceee 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/EncryptedFileKey.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/EncryptedFileKey.kt @@ -77,4 +77,3 @@ data class EncryptedFileKey( return true } } - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/EncryptedMessage.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/EncryptedMessage.kt index bd070e3186..c546cd04c4 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/EncryptedMessage.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/EncryptedMessage.kt @@ -16,7 +16,6 @@ package im.vector.matrix.android.internal.crypto.model.rest - import com.squareup.moshi.Json import com.squareup.moshi.JsonClass diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/ForwardedRoomKeyContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/ForwardedRoomKeyContent.kt index b887989f23..cf8652352c 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/ForwardedRoomKeyContent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/ForwardedRoomKeyContent.kt @@ -44,4 +44,4 @@ data class ForwardedRoomKeyContent( @Json(name = "sender_claimed_ed25519_key") val senderClaimedEd25519Key: String? = null -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/KeyVerificationCancel.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/KeyVerificationCancel.kt index 1d4a9b345a..b5c45e9566 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/KeyVerificationCancel.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/KeyVerificationCancel.kt @@ -57,4 +57,4 @@ data class KeyVerificationCancel( } return true } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/KeyVerificationKey.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/KeyVerificationKey.kt index b5e3323236..4c6243fee3 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/KeyVerificationKey.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/KeyVerificationKey.kt @@ -18,7 +18,6 @@ package im.vector.matrix.android.internal.crypto.model.rest import com.squareup.moshi.Json import com.squareup.moshi.JsonClass - /** * Sent by both devices to send their ephemeral Curve25519 public key to the other device. */ @@ -54,5 +53,4 @@ data class KeyVerificationKey( } return true } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/KeyVerificationMac.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/KeyVerificationMac.kt index 19dbbe5dda..8732e366d2 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/KeyVerificationMac.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/KeyVerificationMac.kt @@ -62,5 +62,4 @@ data class KeyVerificationMac( } } } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/KeyVerificationStart.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/KeyVerificationStart.kt index b042e32fef..081b19161a 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/KeyVerificationStart.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/KeyVerificationStart.kt @@ -74,7 +74,6 @@ class KeyVerificationStart : SendToDeviceObject { @Json(name = "short_authentication_string") var shortAuthenticationStrings: List? = null - companion object { const val VERIF_METHOD_SAS = "m.sas.v1" } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/KeysClaimBody.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/KeysClaimBody.kt index 3ae5ba20ad..87b9891ffa 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/KeysClaimBody.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/KeysClaimBody.kt @@ -37,4 +37,3 @@ data class KeysClaimBody( @Json(name = "one_time_keys") var oneTimeKeys: Map> ) - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/KeysClaimResponse.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/KeysClaimResponse.kt index 989267946b..976743d8bc 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/KeysClaimResponse.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/KeysClaimResponse.kt @@ -32,4 +32,3 @@ data class KeysClaimResponse( @Json(name = "one_time_keys") var oneTimeKeys: Map>>>? = null ) - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/KeysUploadResponse.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/KeysUploadResponse.kt index 72e148baf5..b68c13bf4d 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/KeysUploadResponse.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/KeysUploadResponse.kt @@ -51,4 +51,3 @@ data class KeysUploadResponse( return oneTimeKeyCounts?.containsKey(algorithm) == true } } - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/RoomKeyShare.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/RoomKeyShare.kt index 5d7d49f564..00ad490e1d 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/RoomKeyShare.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/RoomKeyShare.kt @@ -35,4 +35,4 @@ open class RoomKeyShare : SendToDeviceObject { const val ACTION_SHARE_REQUEST = "request" const val ACTION_SHARE_CANCELLATION = "request_cancellation" } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/RoomKeyShareCancellation.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/RoomKeyShareCancellation.kt index d763c5544b..768c2d71c5 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/RoomKeyShareCancellation.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/RoomKeyShareCancellation.kt @@ -25,4 +25,4 @@ class RoomKeyShareCancellation : RoomKeyShare() { init { action = ACTION_SHARE_CANCELLATION } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/RoomKeyShareRequest.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/RoomKeyShareRequest.kt index 4374325870..0d8f7f8738 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/RoomKeyShareRequest.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/RoomKeyShareRequest.kt @@ -29,4 +29,4 @@ class RoomKeyShareRequest : RoomKeyShare() { init { action = ACTION_SHARE_REQUEST } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/SendToDeviceBody.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/SendToDeviceBody.kt index 0c873e8247..8b95d7c686 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/SendToDeviceBody.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/SendToDeviceBody.kt @@ -25,4 +25,4 @@ class SendToDeviceBody { * The device ID may also be *, meaning all known devices for the user. */ var messages: Map>? = null -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/UpdateDeviceInfoBody.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/UpdateDeviceInfoBody.kt index 3a7da69db8..161c5d0354 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/UpdateDeviceInfoBody.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/UpdateDeviceInfoBody.kt @@ -29,4 +29,3 @@ data class UpdateDeviceInfoBody( var displayName: String? = null ) - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/repository/WarnOnUnknownDeviceRepository.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/repository/WarnOnUnknownDeviceRepository.kt index 24d213cfdb..879e565b57 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/repository/WarnOnUnknownDeviceRepository.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/repository/WarnOnUnknownDeviceRepository.kt @@ -41,5 +41,4 @@ internal class WarnOnUnknownDeviceRepository @Inject constructor() { fun setWarnOnUnknownDevices(warn: Boolean) { warnOnUnknownDevices = warn } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/IMXCryptoStore.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/IMXCryptoStore.kt index 1b19db2b89..4e8dfcb2b0 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/IMXCryptoStore.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/IMXCryptoStore.kt @@ -179,7 +179,7 @@ internal interface IMXCryptoStore { * @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) + fun storeUserDevices(userId: String, devices: Map?) /** * Retrieve the known devices for a user. diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/Helper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/Helper.kt index 4ba484ae1a..5ef2b9b1a2 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/Helper.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/Helper.kt @@ -27,46 +27,42 @@ import java.io.ObjectInputStream import java.io.ObjectOutputStream import java.util.zip.GZIPInputStream - /** * Get realm, invoke the action, close realm, and return the result of the action */ fun doWithRealm(realmConfiguration: RealmConfiguration, action: (Realm) -> T): T { - val realm = Realm.getInstance(realmConfiguration) - val result = action.invoke(realm) - realm.close() - return result + return Realm.getInstance(realmConfiguration).use { realm -> + action.invoke(realm) + } } /** * Get realm, do the query, copy from realm, close realm, and return the copied result */ fun doRealmQueryAndCopy(realmConfiguration: RealmConfiguration, action: (Realm) -> T?): T? { - val realm = Realm.getInstance(realmConfiguration) - val result = action.invoke(realm) - val copiedResult = result?.let { realm.copyFromRealm(result) } - realm.close() - return copiedResult + return Realm.getInstance(realmConfiguration).use { realm -> + val result = action.invoke(realm) + result?.let { realm.copyFromRealm(it) } + } } /** * Get realm, do the list query, copy from realm, close realm, and return the copied result */ fun doRealmQueryAndCopyList(realmConfiguration: RealmConfiguration, action: (Realm) -> Iterable): Iterable { - val realm = Realm.getInstance(realmConfiguration) - val result = action.invoke(realm) - val copiedResult = realm.copyFromRealm(result) - realm.close() - return copiedResult + return Realm.getInstance(realmConfiguration).use { realm -> + val result = action.invoke(realm) + realm.copyFromRealm(result) + } } /** * Get realm instance, invoke the action in a transaction and close realm */ fun doRealmTransaction(realmConfiguration: RealmConfiguration, action: (Realm) -> Unit) { - val realm = Realm.getInstance(realmConfiguration) - realm.executeTransaction { action.invoke(it) } - realm.close() + Realm.getInstance(realmConfiguration).use { realm -> + realm.executeTransaction { action.invoke(realm) } + } } /** @@ -101,6 +97,7 @@ fun deserializeFromRealm(string: String?): T? { val gzis = GZIPInputStream(bais) val ois = ObjectInputStream(gzis) + @Suppress("UNCHECKED_CAST") val result = ois.readObject() as T ois.close() diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStore.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStore.kt index 9865614c9f..d88a84de9e 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStore.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStore.kt @@ -16,7 +16,6 @@ package im.vector.matrix.android.internal.crypto.store.db -import android.text.TextUtils import im.vector.matrix.android.api.auth.data.Credentials import im.vector.matrix.android.internal.crypto.IncomingRoomKeyRequest import im.vector.matrix.android.internal.crypto.NewSessionListener @@ -60,7 +59,6 @@ internal class RealmCryptoStore(private val realmConfiguration: RealmConfigurati // Cache for InboundGroupSession, to release them properly private val inboundGroupSessionToRelease = HashMap() - private val newSessionListeners = ArrayList() override fun addNewSessionListener(listener: NewSessionListener) { @@ -102,8 +100,8 @@ internal class RealmCryptoStore(private val realmConfiguration: RealmConfigurati // Check credentials // The device id may not have been provided in credentials. // Check it only if provided, else trust the stored one. - if (!TextUtils.equals(currentMetadata.userId, credentials.userId) - || (credentials.deviceId != null && !TextUtils.equals(credentials.deviceId, currentMetadata.deviceId))) { + if (currentMetadata.userId != credentials.userId + || (credentials.deviceId != null && credentials.deviceId != currentMetadata.deviceId)) { Timber.w("## open() : Credentials do not match, close this store and delete data") deleteAll = true currentMetadata = null @@ -209,10 +207,7 @@ internal class RealmCryptoStore(private val realmConfiguration: RealmConfigurati ?.getDeviceInfo() } - override fun storeUserDevices(userId: String, devices: Map) { - if (userId == null) { - return - } + override fun storeUserDevices(userId: String, devices: Map?) { doRealmTransaction(realmConfiguration) { realm -> if (devices == null) { // Remove the user @@ -281,7 +276,7 @@ internal class RealmCryptoStore(private val realmConfiguration: RealmConfigurati try { sessionIdentifier = olmSessionWrapper.olmSession.sessionIdentifier() } catch (e: OlmException) { - Timber.e(e, "## storeSession() : sessionIdentifier failed " + e.message) + Timber.e(e, "## storeSession() : sessionIdentifier failed") } if (sessionIdentifier != null) { @@ -360,14 +355,14 @@ internal class RealmCryptoStore(private val realmConfiguration: RealmConfigurati return } - doRealmTransaction(realmConfiguration) { + doRealmTransaction(realmConfiguration) { realm -> sessions.forEach { session -> var sessionIdentifier: String? = null try { sessionIdentifier = session.olmInboundGroupSession?.sessionIdentifier() } catch (e: OlmException) { - Timber.e(e, "## storeInboundGroupSession() : sessionIdentifier failed " + e.message) + Timber.e(e, "## storeInboundGroupSession() : sessionIdentifier failed") } if (sessionIdentifier != null) { @@ -387,7 +382,7 @@ internal class RealmCryptoStore(private val realmConfiguration: RealmConfigurati putInboundGroupSession(session) } - it.insertOrUpdate(realmOlmInboundGroupSession) + realm.insertOrUpdate(realmOlmInboundGroupSession) } } } @@ -737,5 +732,4 @@ internal class RealmCryptoStore(private val realmConfiguration: RealmConfigurati } .toMutableList() } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStoreModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStoreModule.kt index ff2f6cc42e..998274020a 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStoreModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStoreModule.kt @@ -34,4 +34,4 @@ import io.realm.annotations.RealmModule OutgoingRoomKeyRequestEntity::class, UserEntity::class ]) -internal class RealmCryptoStoreModule \ No newline at end of file +internal class RealmCryptoStoreModule diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/model/CryptoMetadataEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/model/CryptoMetadataEntity.kt index 2c96bb25ed..eae202f966 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/model/CryptoMetadataEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/model/CryptoMetadataEntity.kt @@ -37,7 +37,6 @@ internal open class CryptoMetadataEntity( var backupVersion: String? = null ) : RealmObject() { - // Deserialize data fun getOlmAccount(): OlmAccount? { return deserializeFromRealm(olmAccountData) @@ -47,4 +46,4 @@ internal open class CryptoMetadataEntity( fun putOlmAccount(olmAccount: OlmAccount?) { olmAccountData = serializeForRealm(olmAccount) } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/model/CryptoRoomEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/model/CryptoRoomEntity.kt index fcec259ed9..531f44a838 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/model/CryptoRoomEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/model/CryptoRoomEntity.kt @@ -27,5 +27,4 @@ internal open class CryptoRoomEntity( : RealmObject() { companion object - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/model/IncomingRoomKeyRequestEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/model/IncomingRoomKeyRequestEntity.kt index 707418ab7e..9b1d116aa9 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/model/IncomingRoomKeyRequestEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/model/IncomingRoomKeyRequestEntity.kt @@ -53,4 +53,4 @@ internal open class IncomingRoomKeyRequestEntity( requestBodySessionId = it.sessionId } } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/model/KeysBackupDataEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/model/KeysBackupDataEntity.kt index 53ebf146d8..f88202dead 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/model/KeysBackupDataEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/model/KeysBackupDataEntity.kt @@ -27,4 +27,4 @@ internal open class KeysBackupDataEntity( var backupLastServerHash: String? = null, // The last known number of backed up keys on the server var backupLastServerNumberOfKeys: Int? = null -) : RealmObject() \ No newline at end of file +) : RealmObject() diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/model/OlmInboundGroupSessionEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/model/OlmInboundGroupSessionEntity.kt index 4835300e66..caa8cb9668 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/model/OlmInboundGroupSessionEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/model/OlmInboundGroupSessionEntity.kt @@ -44,4 +44,4 @@ internal open class OlmInboundGroupSessionEntity( } companion object -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/model/OlmSessionEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/model/OlmSessionEntity.kt index dbc860eff0..c051fe56a2 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/model/OlmSessionEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/model/OlmSessionEntity.kt @@ -41,4 +41,4 @@ internal open class OlmSessionEntity(@PrimaryKey var primaryKey: String = "", } companion object -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/model/OutgoingRoomKeyRequestEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/model/OutgoingRoomKeyRequestEntity.kt index d468285882..b7bcb603f5 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/model/OutgoingRoomKeyRequestEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/model/OutgoingRoomKeyRequestEntity.kt @@ -73,5 +73,3 @@ internal open class OutgoingRoomKeyRequestEntity( } } } - - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/query/UserEntitiesQueries.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/query/UserEntitiesQueries.kt index 3860d8d8ce..8088a14825 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/query/UserEntitiesQueries.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/query/UserEntitiesQueries.kt @@ -42,4 +42,3 @@ internal fun UserEntity.Companion.delete(realm: Realm, userId: String) { .findFirst() ?.deleteFromRealm() } - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/tasks/ClaimOneTimeKeysForUsersDeviceTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/tasks/ClaimOneTimeKeysForUsersDeviceTask.kt index 23b0f958bf..80f326e083 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/tasks/ClaimOneTimeKeysForUsersDeviceTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/tasks/ClaimOneTimeKeysForUsersDeviceTask.kt @@ -44,18 +44,14 @@ internal class DefaultClaimOneTimeKeysForUsersDevice @Inject constructor(private } val map = MXUsersDevicesMap() keysClaimResponse.oneTimeKeys?.let { oneTimeKeys -> - for (userId in oneTimeKeys.keys) { - val mapByUserId = oneTimeKeys[userId] + for ((userId, mapByUserId) in oneTimeKeys) { + for ((deviceId, deviceKey) in mapByUserId) { + val mxKey = MXKey.from(deviceKey) - if (mapByUserId != null) { - for (deviceId in mapByUserId.keys) { - val mxKey = MXKey.from(mapByUserId[deviceId]) - - if (mxKey != null) { - map.setObject(userId, deviceId, mxKey) - } else { - Timber.e("## claimOneTimeKeysForUsersDevices : fail to create a MXKey") - } + if (mxKey != null) { + map.setObject(userId, deviceId, mxKey) + } else { + Timber.e("## claimOneTimeKeysForUsersDevices : fail to create a MXKey") } } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/tasks/DeleteDeviceTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/tasks/DeleteDeviceTask.kt index 3e6e4d8ca2..0e52c118d9 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/tasks/DeleteDeviceTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/tasks/DeleteDeviceTask.kt @@ -55,7 +55,6 @@ internal class DefaultDeleteDeviceTask @Inject constructor(private val cryptoApi } else { throw throwable } - } else { // Other error throw throwable diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/tasks/DownloadKeysForUsersTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/tasks/DownloadKeysForUsersTask.kt index 92908071a1..230af3874e 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/tasks/DownloadKeysForUsersTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/tasks/DownloadKeysForUsersTask.kt @@ -16,13 +16,11 @@ package im.vector.matrix.android.internal.crypto.tasks -import android.text.TextUtils import im.vector.matrix.android.internal.crypto.api.CryptoApi import im.vector.matrix.android.internal.crypto.model.rest.KeysQueryBody import im.vector.matrix.android.internal.crypto.model.rest.KeysQueryResponse import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.task.Task -import java.util.* import javax.inject.Inject internal interface DownloadKeysForUsersTask : Task { @@ -37,19 +35,13 @@ internal class DefaultDownloadKeysForUsers @Inject constructor(private val crypt : DownloadKeysForUsersTask { override suspend fun execute(params: DownloadKeysForUsersTask.Params): KeysQueryResponse { - val downloadQuery = HashMap>() - - if (null != params.userIds) { - for (userId in params.userIds) { - downloadQuery[userId] = HashMap() - } - } + val downloadQuery = params.userIds?.associateWith { emptyMap() }.orEmpty() val body = KeysQueryBody( deviceKeys = downloadQuery ) - if (!TextUtils.isEmpty(params.token)) { + if (!params.token.isNullOrEmpty()) { body.token = params.token } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/tasks/SetDeviceNameTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/tasks/SetDeviceNameTask.kt index 1abef5763e..47f3050b88 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/tasks/SetDeviceNameTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/tasks/SetDeviceNameTask.kt @@ -16,7 +16,6 @@ package im.vector.matrix.android.internal.crypto.tasks -import android.text.TextUtils import im.vector.matrix.android.internal.crypto.api.CryptoApi import im.vector.matrix.android.internal.crypto.model.rest.UpdateDeviceInfoBody import im.vector.matrix.android.internal.network.executeRequest @@ -37,7 +36,7 @@ internal class DefaultSetDeviceNameTask @Inject constructor(private val cryptoAp override suspend fun execute(params: SetDeviceNameTask.Params) { val body = UpdateDeviceInfoBody( - displayName = if (TextUtils.isEmpty(params.deviceName)) "" else params.deviceName + displayName = params.deviceName ) return executeRequest { apiCall = cryptoApi.updateDeviceInfo(params.deviceId, body) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/DefaultSasVerificationService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/DefaultSasVerificationService.kt index e071fc8571..ca1157e583 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/DefaultSasVerificationService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/DefaultSasVerificationService.kt @@ -37,7 +37,6 @@ import im.vector.matrix.android.internal.crypto.model.rest.* import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore import im.vector.matrix.android.internal.crypto.tasks.SendToDeviceTask import im.vector.matrix.android.internal.session.SessionScope -import im.vector.matrix.android.internal.task.TaskConstraints import im.vector.matrix.android.internal.task.TaskExecutor import im.vector.matrix.android.internal.task.configureWith import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers @@ -90,7 +89,7 @@ internal class DefaultSasVerificationService @Inject constructor(private val cre onMacReceived(event) } else -> { - //ignore + // ignore } } } @@ -120,7 +119,6 @@ internal class DefaultSasVerificationService @Inject constructor(private val cre } catch (e: Throwable) { Timber.e(e, "## Error while notifying listeners") } - } } } @@ -167,7 +165,7 @@ internal class DefaultSasVerificationService @Inject constructor(private val cre } return } - //Download device keys prior to everything + // Download device keys prior to everything checkKeysAreDownloaded( otherUserId!!, startReq, @@ -177,19 +175,19 @@ internal class DefaultSasVerificationService @Inject constructor(private val cre val existing = getExistingTransaction(otherUserId, tid) val existingTxs = getExistingTransactionsForUser(otherUserId) if (existing != null) { - //should cancel both! + // should cancel both! Timber.v("## SAS onStartRequestReceived - Request exist with same if ${startReq.transactionID!!}") existing.cancel(CancelCode.UnexpectedMessage) cancelTransaction(tid, otherUserId, startReq.fromDevice!!, CancelCode.UnexpectedMessage) } else if (existingTxs?.isEmpty() == false) { Timber.v("## SAS onStartRequestReceived - There is already a transaction with this user ${startReq.transactionID!!}") - //Multiple keyshares between two devices: any two devices may only have at most one key verification in flight at a time. + // Multiple keyshares between two devices: any two devices may only have at most one key verification in flight at a time. existingTxs.forEach { it.cancel(CancelCode.UnexpectedMessage) } cancelTransaction(tid, otherUserId, startReq.fromDevice!!, CancelCode.UnexpectedMessage) } else { - //Ok we can create + // Ok we can create if (KeyVerificationStart.VERIF_METHOD_SAS == startReq.method) { Timber.v("## SAS onStartRequestReceived - request accepted ${startReq.transactionID!!}") val tx = IncomingSASVerificationTransaction( @@ -241,7 +239,7 @@ internal class DefaultSasVerificationService @Inject constructor(private val cre val cancelReq = event.getClearContent().toModel()!! if (!cancelReq.isValid()) { - //ignore + // ignore Timber.e("## Received invalid accept request") return } @@ -263,7 +261,7 @@ internal class DefaultSasVerificationService @Inject constructor(private val cre val acceptReq = event.getClearContent().toModel()!! if (!acceptReq.isValid()) { - //ignore + // ignore Timber.e("## Received invalid accept request") return } @@ -272,22 +270,20 @@ internal class DefaultSasVerificationService @Inject constructor(private val cre if (existing == null) { Timber.e("## Received invalid accept request") return - } if (existing is SASVerificationTransaction) { existing.acceptToDeviceEvent(otherUserId, acceptReq) } else { - //not other types now + // not other types now } } - private suspend fun onKeyReceived(event: Event) { val keyReq = event.getClearContent().toModel()!! if (!keyReq.isValid()) { - //ignore + // ignore Timber.e("## Received invalid key request") return } @@ -300,7 +296,7 @@ internal class DefaultSasVerificationService @Inject constructor(private val cre if (existing is SASVerificationTransaction) { existing.acceptToDeviceEvent(otherUserId, keyReq) } else { - //not other types now + // not other types now } } @@ -308,7 +304,7 @@ internal class DefaultSasVerificationService @Inject constructor(private val cre val macReq = event.getClearContent().toModel()!! if (!macReq.isValid()) { - //ignore + // ignore Timber.e("## Received invalid key request") return } @@ -321,7 +317,7 @@ internal class DefaultSasVerificationService @Inject constructor(private val cre if (existing is SASVerificationTransaction) { existing.acceptToDeviceEvent(otherUserId, macReq) } else { - //not other types known for now + // not other types known for now } } @@ -362,7 +358,7 @@ internal class DefaultSasVerificationService @Inject constructor(private val cre override fun beginKeyVerification(method: String, userId: String, deviceID: String): String? { val txID = createUniqueIDForTransaction(userId, deviceID) - //should check if already one (and cancel it) + // should check if already one (and cancel it) if (KeyVerificationStart.VERIF_METHOD_SAS == method) { val tx = OutgoingSASVerificationRequest( this, @@ -397,7 +393,6 @@ internal class DefaultSasVerificationService @Inject constructor(private val cre } } - override fun transactionUpdated(tx: VerificationTransaction) { dispatchTxUpdated(tx) if (tx is SASVerificationTransaction @@ -405,7 +400,7 @@ internal class DefaultSasVerificationService @Inject constructor(private val cre || tx.state == SasVerificationTxState.OnCancelled || tx.state == SasVerificationTxState.Verified) ) { - //remove + // remove this.removeTransaction(tx.otherUserId, tx.transactionId) } } @@ -429,4 +424,4 @@ internal class DefaultSasVerificationService @Inject constructor(private val cre } .executeBy(taskExecutor) } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/IncomingSASVerificationTransaction.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/IncomingSASVerificationTransaction.kt index 641062d7f2..6ed5be4881 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/IncomingSASVerificationTransaction.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/IncomingSASVerificationTransaction.kt @@ -82,16 +82,14 @@ internal class IncomingSASVerificationTransaction( Timber.v("## SAS received verification request from state $state") if (state != SasVerificationTxState.None) { Timber.e("## received verification request from invalid state") - //should I cancel?? + // should I cancel?? throw IllegalStateException("Interactive Key verification already started") } this.startReq = startReq state = SasVerificationTxState.OnStarted this.otherDeviceId = startReq.fromDevice - } - override fun performAccept() { if (state != SasVerificationTxState.OnStarted) { Timber.e("## Cannot perform accept from state $state") @@ -105,29 +103,29 @@ internal class IncomingSASVerificationTransaction( val agreedMac = startReq!!.messageAuthenticationCodes?.firstOrNull { KNOWN_MACS.contains(it) } val agreedShortCode = startReq!!.shortAuthenticationStrings?.filter { KNOWN_SHORT_CODES.contains(it) } - //No common key sharing/hashing/hmac/SAS methods. - //If a device is unable to complete the verification because the devices are unable to find a common key sharing, + // No common key sharing/hashing/hmac/SAS methods. + // If a device is unable to complete the verification because the devices are unable to find a common key sharing, // hashing, hmac, or SAS method, then it should send a m.key.verification.cancel message if (listOf(agreedProtocol, agreedHash, agreedMac).any { it.isNullOrBlank() } || agreedShortCode.isNullOrEmpty()) { - //Failed to find agreement + // Failed to find agreement Timber.e("## Failed to find agreement ") cancel(CancelCode.UnknownMethod) return } - //Bob’s device ensures that it has a copy of Alice’s device key. + // Bob’s device ensures that it has a copy of Alice’s device key. val mxDeviceInfo = cryptoStore.getUserDevice(deviceId = otherDeviceId!!, userId = otherUserId) if (mxDeviceInfo?.fingerprint() == null) { Timber.e("## Failed to find device key ") - //TODO force download keys!! - //would be probably better to download the keys - //for now I cancel + // TODO force download keys!! + // would be probably better to download the keys + // for now I cancel cancel(CancelCode.User) } else { // val otherKey = info.identityKey() - //need to jump back to correct thread + // need to jump back to correct thread val accept = KeyVerificationAccept.create( tid = transactionId, keyAgreementProtocol = agreedProtocol!!, @@ -140,26 +138,24 @@ internal class IncomingSASVerificationTransaction( } } - private fun doAccept(accept: KeyVerificationAccept) { this.accepted = accept Timber.v("## SAS accept request id:$transactionId") - //The hash commitment is the hash (using the selected hash algorithm) of the unpadded base64 representation of QB, + // The hash commitment is the hash (using the selected hash algorithm) of the unpadded base64 representation of QB, // concatenated with the canonical JSON representation of the content of the m.key.verification.start message val concat = getSAS().publicKey + JsonCanonicalizer.getCanonicalJson(KeyVerificationStart::class.java, startReq!!) accept.commitment = hashUsingAgreedHashMethod(concat) ?: "" - //we need to send this to other device now + // we need to send this to other device now state = SasVerificationTxState.SendingAccept sendToOther(EventType.KEY_VERIFICATION_ACCEPT, accept, SasVerificationTxState.Accepted, CancelCode.User) { if (state == SasVerificationTxState.SendingAccept) { - //It is possible that we receive the next event before this one :/, in this case we should keep state + // It is possible that we receive the next event before this one :/, in this case we should keep state state = SasVerificationTxState.Accepted } } } - override fun onVerificationAccept(accept: KeyVerificationAccept) { Timber.v("## SAS invalid message for incoming request id:$transactionId") cancel(CancelCode.UnexpectedMessage) @@ -180,11 +176,11 @@ internal class IncomingSASVerificationTransaction( val pubKey = getSAS().publicKey val keyToDevice = KeyVerificationKey.create(transactionId, pubKey) - //we need to send this to other device now + // we need to send this to other device now state = SasVerificationTxState.SendingKey this.sendToOther(EventType.KEY_VERIFICATION_KEY, keyToDevice, SasVerificationTxState.KeySent, CancelCode.User) { if (state == SasVerificationTxState.SendingKey) { - //It is possible that we receive the next event before this one :/, in this case we should keep state + // It is possible that we receive the next event before this one :/, in this case we should keep state state = SasVerificationTxState.KeySent } } @@ -194,7 +190,7 @@ internal class IncomingSASVerificationTransaction( // using the result as the shared secret. getSAS().setTheirPublicKey(otherKey) - //(Note: In all of the following HKDF is as defined in RFC 5869, and uses the previously agreed-on hash function as the hash function, + // (Note: In all of the following HKDF is as defined in RFC 5869, and uses the previously agreed-on hash function as the hash function, // the shared secret as the input keying material, no salt, and with the input parameter set to the concatenation of: // - the string “MATRIX_KEY_VERIFICATION_SAS”, // - the Matrix ID of the user who sent the m.key.verification.start message, @@ -206,8 +202,8 @@ internal class IncomingSASVerificationTransaction( "$otherUserId$otherDeviceId" + "${credentials.userId}${credentials.deviceId}" + transactionId - //decimal: generate five bytes by using HKDF. - //emoji: generate six bytes by using HKDF. + // decimal: generate five bytes by using HKDF. + // emoji: generate six bytes by using HKDF. shortCodeBytes = getSAS().generateShortCode(sasInfo, 6) Timber.e("************ BOB CODE ${getDecimalCodeRepresentation(shortCodeBytes!!)}") @@ -218,7 +214,7 @@ internal class IncomingSASVerificationTransaction( override fun onKeyVerificationMac(vKey: KeyVerificationMac) { Timber.v("## SAS received mac for request id:$transactionId") - //Check for state? + // Check for state? if (state != SasVerificationTxState.SendingKey && state != SasVerificationTxState.KeySent && state != SasVerificationTxState.ShortCodeReady @@ -231,11 +227,11 @@ internal class IncomingSASVerificationTransaction( } theirMac = vKey - //Do I have my Mac? + // Do I have my Mac? if (myMac != null) { - //I can check + // I can check verifyMacs() } - //Wait for ShortCode Accepted + // Wait for ShortCode Accepted } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/OutgoingSASVerificationRequest.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/OutgoingSASVerificationRequest.kt index 0500be5426..cade637cce 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/OutgoingSASVerificationRequest.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/OutgoingSASVerificationRequest.kt @@ -56,7 +56,6 @@ internal class OutgoingSASVerificationRequest( isIncoming = false), OutgoingSasVerificationRequest { - override val uxState: OutgoingSasVerificationRequest.UxState get() { return when (state) { @@ -87,7 +86,7 @@ internal class OutgoingSASVerificationRequest( fun start() { if (state != SasVerificationTxState.None) { Timber.e("## start verification from invalid state") - //should I cancel?? + // should I cancel?? throw IllegalStateException("Interactive Key verification already started") } @@ -119,7 +118,7 @@ internal class OutgoingSASVerificationRequest( cancel(CancelCode.UnexpectedMessage) return } - //Check that the agreement is correct + // Check that the agreement is correct if (!KNOWN_AGREEMENT_PROTOCOLS.contains(accept.keyAgreementProtocol) || !KNOWN_HASHES.contains(accept.hash) || !KNOWN_MACS.contains(accept.messageAuthenticationCode) @@ -129,7 +128,7 @@ internal class OutgoingSASVerificationRequest( return } - //Upon receipt of the m.key.verification.accept message from Bob’s device, + // Upon receipt of the m.key.verification.accept message from Bob’s device, // Alice’s device stores the commitment value for later use. accepted = accept state = SasVerificationTxState.OnAccepted @@ -139,10 +138,10 @@ internal class OutgoingSASVerificationRequest( val pubKey = getSAS().publicKey val keyToDevice = KeyVerificationKey.create(transactionId, pubKey) - //we need to send this to other device now + // we need to send this to other device now state = SasVerificationTxState.SendingKey sendToOther(EventType.KEY_VERIFICATION_KEY, keyToDevice, SasVerificationTxState.KeySent, CancelCode.User) { - //It is possible that we receive the next event before this one :/, in this case we should keep state + // It is possible that we receive the next event before this one :/, in this case we should keep state if (state == SasVerificationTxState.SendingKey) { state = SasVerificationTxState.KeySent } @@ -163,13 +162,13 @@ internal class OutgoingSASVerificationRequest( // message is the same as the expected value based on the value of the key property received // in Bob’s m.key.verification.key and the content of Alice’s m.key.verification.start message. - //check commitment + // check commitment val concat = vKey.key + JsonCanonicalizer.getCanonicalJson(KeyVerificationStart::class.java, startReq!!) val otherCommitment = hashUsingAgreedHashMethod(concat) ?: "" if (accepted!!.commitment.equals(otherCommitment)) { getSAS().setTheirPublicKey(otherKey) - //(Note: In all of the following HKDF is as defined in RFC 5869, and uses the previously agreed-on hash function as the hash function, + // (Note: In all of the following HKDF is as defined in RFC 5869, and uses the previously agreed-on hash function as the hash function, // the shared secret as the input keying material, no salt, and with the input parameter set to the concatenation of: // - the string “MATRIX_KEY_VERIFICATION_SAS”, // - the Matrix ID of the user who sent the m.key.verification.start message, @@ -181,12 +180,12 @@ internal class OutgoingSASVerificationRequest( "${credentials.userId}${credentials.deviceId}" + "$otherUserId$otherDeviceId" + transactionId - //decimal: generate five bytes by using HKDF. - //emoji: generate six bytes by using HKDF. + // decimal: generate five bytes by using HKDF. + // emoji: generate six bytes by using HKDF. shortCodeBytes = getSAS().generateShortCode(sasInfo, 6) state = SasVerificationTxState.ShortCodeReady } else { - //bad commitement + // bad commitement cancel(CancelCode.MismatchedCommitment) } } @@ -205,11 +204,11 @@ internal class OutgoingSASVerificationRequest( theirMac = vKey - //Do I have my Mac? + // Do I have my Mac? if (myMac != null) { - //I can check + // I can check verifyMacs() } - //Wait for ShortCode Accepted + // Wait for ShortCode Accepted } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/SASVerificationTransaction.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/SASVerificationTransaction.kt index de4b997410..589103d38a 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/SASVerificationTransaction.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/SASVerificationTransaction.kt @@ -59,20 +59,20 @@ internal abstract class SASVerificationTransaction( const val SAS_MAC_SHA256_LONGKDF = "hmac-sha256" const val SAS_MAC_SHA256 = "hkdf-hmac-sha256" - //ordered by preferred order + // ordered by preferred order val KNOWN_AGREEMENT_PROTOCOLS = listOf(MXKey.KEY_CURVE_25519_TYPE) - //ordered by preferred order + // ordered by preferred order val KNOWN_HASHES = listOf("sha256") - //ordered by preferred order + // ordered by preferred order val KNOWN_MACS = listOf(SAS_MAC_SHA256, SAS_MAC_SHA256_LONGKDF) - //older devices have limited support of emoji, so reply with decimal + // older devices have limited support of emoji, so reply with decimal val KNOWN_SHORT_CODES = - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { listOf(SasMode.EMOJI, SasMode.DECIMAL) - else + } else { listOf(SasMode.DECIMAL) - + } } override var state by Delegates.observable(SasVerificationTxState.None) { _, _, new -> @@ -108,7 +108,7 @@ internal abstract class SASVerificationTransaction( return olmSas!! } - //To override finalize(), all you need to do is simply declare it, without using the override keyword: + // To override finalize(), all you need to do is simply declare it, without using the override keyword: protected fun finalize() { releaseSAS() } @@ -119,7 +119,6 @@ internal abstract class SASVerificationTransaction( olmSas = null } - /** * To be called by the client when the user has verified that * both short codes do match @@ -127,16 +126,16 @@ internal abstract class SASVerificationTransaction( override fun userHasVerifiedShortCode() { Timber.v("## SAS short code verified by user for id:$transactionId") if (state != SasVerificationTxState.ShortCodeReady) { - //ignore and cancel? + // ignore and cancel? Timber.e("## Accepted short code from invalid state $state") cancel(CancelCode.UnexpectedMessage) return } state = SasVerificationTxState.ShortCodeAccepted - //Alice and Bob’ devices calculate the HMAC of their own device keys and a comma-separated, + // Alice and Bob’ devices calculate the HMAC of their own device keys and a comma-separated, // sorted list of the key IDs that they wish the other user to verify, - //the shared secret as the input keying material, no salt, and with the input parameter set to the concatenation of: + // the shared secret as the input keying material, no salt, and with the input parameter set to the concatenation of: // - the string “MATRIX_KEY_VERIFICATION_MAC”, // - the Matrix ID of the user whose key is being MAC-ed, // - the device ID of the device sending the MAC, @@ -155,7 +154,7 @@ internal abstract class SASVerificationTransaction( val keyStrings = macUsingAgreedMethod(keyId, baseInfo + "KEY_IDS") if (macString.isNullOrBlank() || keyStrings.isNullOrBlank()) { - //Should not happen + // Should not happen Timber.e("## SAS verification [$transactionId] failed to send KeyMac, empty key hashes.") cancel(CancelCode.UnexpectedMessage) return @@ -166,16 +165,15 @@ internal abstract class SASVerificationTransaction( state = SasVerificationTxState.SendingMac sendToOther(EventType.KEY_VERIFICATION_MAC, macMsg, SasVerificationTxState.MacSent, CancelCode.User) { if (state == SasVerificationTxState.SendingMac) { - //It is possible that we receive the next event before this one :/, in this case we should keep state + // It is possible that we receive the next event before this one :/, in this case we should keep state state = SasVerificationTxState.MacSent } } - //Do I already have their Mac? + // Do I already have their Mac? if (theirMac != null) { verifyMacs() - } //if not wait for it - + } // if not wait for it } override fun acceptToDeviceEvent(senderId: String, event: SendToDeviceObject) { @@ -185,7 +183,7 @@ internal abstract class SASVerificationTransaction( is KeyVerificationKey -> onKeyVerificationKey(senderId, event) is KeyVerificationMac -> onKeyVerificationMac(event) else -> { - //nop + // nop } } } @@ -202,7 +200,7 @@ internal abstract class SASVerificationTransaction( Timber.v("## SAS verifying macs for id:$transactionId") state = SasVerificationTxState.Verifying - //Keys have been downloaded earlier in process + // Keys have been downloaded earlier in process val otherUserKnownDevices = cryptoStore.getUserDevices(otherUserId) // Bob’s device calculates the HMAC (as above) of its copies of Alice’s keys given in the message (as identified by their key ID), @@ -219,25 +217,25 @@ internal abstract class SASVerificationTransaction( val keyStrings = macUsingAgreedMethod(commaSeparatedListOfKeyIds, baseInfo + "KEY_IDS") if (theirMac!!.keys != keyStrings) { - //WRONG! + // WRONG! cancel(CancelCode.MismatchedKeys) return } val verifiedDevices = ArrayList() - //cannot be empty because it has been validated + // cannot be empty because it has been validated theirMac!!.mac!!.keys.forEach { val keyIDNoPrefix = if (it.startsWith("ed25519:")) it.substring("ed25519:".length) else it val otherDeviceKey = otherUserKnownDevices?.get(keyIDNoPrefix)?.fingerprint() if (otherDeviceKey == null) { Timber.e("Verification: Could not find device $keyIDNoPrefix to verify") - //just ignore and continue + // just ignore and continue return@forEach } val mac = macUsingAgreedMethod(otherDeviceKey, baseInfo + it) if (mac != theirMac?.mac?.get(it)) { - //WRONG! + // WRONG! cancel(CancelCode.MismatchedKeys) return } @@ -252,7 +250,7 @@ internal abstract class SASVerificationTransaction( return } - //TODO what if the otherDevice is not in this list? and should we + // TODO what if the otherDevice is not in this list? and should we verifiedDevices.forEach { setDeviceVerified(it, otherUserId) } @@ -370,16 +368,16 @@ internal abstract class SASVerificationTransaction( * or with the three numbers on separate lines. */ fun getDecimalCodeRepresentation(byteArray: ByteArray): String { - val b0 = byteArray[0].toUnsignedInt() //need unsigned byte - val b1 = byteArray[1].toUnsignedInt() //need unsigned byte - val b2 = byteArray[2].toUnsignedInt() //need unsigned byte - val b3 = byteArray[3].toUnsignedInt() //need unsigned byte - val b4 = byteArray[4].toUnsignedInt() //need unsigned byte - //(B0 << 5 | B1 >> 3) + 1000 + val b0 = byteArray[0].toUnsignedInt() // need unsigned byte + val b1 = byteArray[1].toUnsignedInt() // need unsigned byte + val b2 = byteArray[2].toUnsignedInt() // need unsigned byte + val b3 = byteArray[3].toUnsignedInt() // need unsigned byte + val b4 = byteArray[4].toUnsignedInt() // need unsigned byte + // (B0 << 5 | B1 >> 3) + 1000 val first = (b0.shl(5) or b1.shr(3)) + 1000 - //((B1 & 0x7) << 10 | B2 << 2 | B3 >> 6) + 1000 + // ((B1 & 0x7) << 10 | B2 << 2 | B3 >> 6) + 1000 val second = ((b1 and 0x7).shl(10) or b2.shl(2) or b3.shr(6)) + 1000 - //((B3 & 0x3f) << 7 | B4 >> 1) + 1000 + // ((B3 & 0x3f) << 7 | B4 >> 1) + 1000 val third = ((b3 and 0x3f).shl(7) or b4.shr(1)) + 1000 return "$first $second $third" } @@ -411,5 +409,4 @@ internal abstract class SASVerificationTransaction( getEmojiForCode((b4 and 0xF).shl(2) or (b5 and 0xC0).shr(6)) ) } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/AsyncTransaction.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/AsyncTransaction.kt index e1beefc2e5..36e68e5cf3 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/AsyncTransaction.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/AsyncTransaction.kt @@ -21,7 +21,6 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.isActive import kotlinx.coroutines.withContext - suspend fun awaitTransaction(config: RealmConfiguration, transaction: suspend (realm: Realm) -> Unit) = withContext(Dispatchers.IO) { Realm.getInstance(config).use { bgRealm -> bgRealm.beginTransaction() @@ -36,4 +35,4 @@ suspend fun awaitTransaction(config: RealmConfiguration, transaction: suspend (r } } } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/DBConstants.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/DBConstants.kt index 0f420f3bbf..3dff2f2273 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/DBConstants.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/DBConstants.kt @@ -19,5 +19,4 @@ package im.vector.matrix.android.internal.database internal object DBConstants { const val STATE_EVENTS_CHUNK_TOKEN = "STATE_EVENTS_CHUNK_TOKEN" - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/RealmKeysUtils.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/RealmKeysUtils.kt index d2ab764087..55ced343d4 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/RealmKeysUtils.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/RealmKeysUtils.kt @@ -117,4 +117,4 @@ internal class RealmKeysUtils @Inject constructor(context: Context, companion object { private const val ENCRYPTED_KEY_PREFIX = "REALM_ENCRYPTED_KEY" } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/RealmLiveData.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/RealmLiveData.kt deleted file mode 100644 index 46a431a412..0000000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/RealmLiveData.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2019 New Vector Ltd - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package im.vector.matrix.android.internal.database - -import androidx.lifecycle.LiveData -import io.realm.* - -class RealmLiveData(private val realmConfiguration: RealmConfiguration, - private val query: (Realm) -> RealmQuery) : LiveData>() { - - private val listener = RealmChangeListener> { results -> - value = results - } - - private var realm: Realm? = null - private var results: RealmResults? = null - - override fun onActive() { - val realm = Realm.getInstance(realmConfiguration) - val results = query.invoke(realm).findAllAsync() - results.addChangeListener(listener) - this.realm = realm - this.results = results - } - - override fun onInactive() { - results?.removeChangeListener(listener) - results = null - realm?.close() - realm = null - } -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/RealmLiveEntityObserver.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/RealmLiveEntityObserver.kt index e78078f93e..9c7a788b44 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/RealmLiveEntityObserver.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/RealmLiveEntityObserver.kt @@ -66,5 +66,4 @@ internal abstract class RealmLiveEntityObserver(protected val r override fun isStarted(): Boolean { return isStarted.get() } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/RealmQueryLatch.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/RealmQueryLatch.kt index 3e3ffad45c..2d386eac15 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/RealmQueryLatch.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/RealmQueryLatch.kt @@ -22,7 +22,6 @@ import java.util.concurrent.CountDownLatch import java.util.concurrent.TimeUnit import java.util.concurrent.atomic.AtomicReference - class RealmQueryLatch(private val realmConfiguration: RealmConfiguration, private val realmQueryBuilder: (Realm) -> RealmQuery) { @@ -57,6 +56,4 @@ class RealmQueryLatch(private val realmConfiguration: RealmConf } } } - - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/SessionRealmConfigurationFactory.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/SessionRealmConfigurationFactory.kt new file mode 100644 index 0000000000..881d7ce2c5 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/SessionRealmConfigurationFactory.kt @@ -0,0 +1,90 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.matrix.android.internal.database + +import android.content.Context +import im.vector.matrix.android.internal.database.model.SessionRealmModule +import im.vector.matrix.android.internal.di.UserCacheDirectory +import im.vector.matrix.android.internal.di.UserMd5 +import im.vector.matrix.android.internal.session.SessionModule +import io.realm.Realm +import io.realm.RealmConfiguration +import timber.log.Timber +import java.io.File +import javax.inject.Inject + +private const val REALM_SHOULD_CLEAR_FLAG_ = "REALM_SHOULD_CLEAR_FLAG_" +private const val REALM_NAME = "disk_store.realm" + +/** + * This class is handling creation of RealmConfiguration for a session. + * It will handle corrupted realm by clearing the db file. It allows to just clear cache without losing your crypto keys. + * It's clearly not perfect but there is no way to catch the native crash. + */ +internal class SessionRealmConfigurationFactory @Inject constructor(private val realmKeysUtils: RealmKeysUtils, + @UserCacheDirectory val directory: File, + @UserMd5 val userMd5: String, + context: Context) { + + private val sharedPreferences = context.getSharedPreferences("im.vector.matrix.android.realm", Context.MODE_PRIVATE) + + fun create(): RealmConfiguration { + val shouldClearRealm = sharedPreferences.getBoolean("$REALM_SHOULD_CLEAR_FLAG_$userMd5", false) + if (shouldClearRealm) { + Timber.v("************************************************************") + Timber.v("The realm file session was corrupted and couldn't be loaded.") + Timber.v("The file has been deleted to recover.") + Timber.v("************************************************************") + deleteRealmFiles() + } + sharedPreferences + .edit() + .putBoolean("$REALM_SHOULD_CLEAR_FLAG_$userMd5", true) + .apply() + + val realmConfiguration = RealmConfiguration.Builder() + .directory(directory) + .name(REALM_NAME) + .apply { + realmKeysUtils.configureEncryption(this, "${SessionModule.DB_ALIAS_PREFIX}$userMd5") + } + .modules(SessionRealmModule()) + .deleteRealmIfMigrationNeeded() + .build() + + // Try creating a realm instance and if it succeeds we can clear the flag + Realm.getInstance(realmConfiguration).use { + Timber.v("Successfully create realm instance") + sharedPreferences + .edit() + .putBoolean("$REALM_SHOULD_CLEAR_FLAG_$userMd5", false) + .apply() + } + return realmConfiguration + } + + // Delete all the realm files of the session + private fun deleteRealmFiles() { + listOf(REALM_NAME, "$REALM_NAME.lock", "$REALM_NAME.note", "$REALM_NAME.management").forEach { file -> + try { + File(directory, file).deleteRecursively() + } catch (e: Exception) { + Timber.e(e, "Unable to move files") + } + } + } +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/ChunkEntityHelper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/ChunkEntityHelper.kt index 69065f5171..e9ffa140c9 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/ChunkEntityHelper.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/ChunkEntityHelper.kt @@ -23,6 +23,7 @@ import im.vector.matrix.android.internal.database.mapper.asDomain import im.vector.matrix.android.internal.database.mapper.toEntity import im.vector.matrix.android.internal.database.model.ChunkEntity import im.vector.matrix.android.internal.database.model.EventAnnotationsSummaryEntity +import im.vector.matrix.android.internal.database.model.ReadMarkerEntity import im.vector.matrix.android.internal.database.model.ReadReceiptEntity import im.vector.matrix.android.internal.database.model.ReadReceiptsSummaryEntity import im.vector.matrix.android.internal.database.model.TimelineEventEntity @@ -110,7 +111,6 @@ internal fun ChunkEntity.add(roomId: String, direction: PaginationDirection, stateIndexOffset: Int = 0, isUnlinked: Boolean = false) { - assertIsManaged() if (event.eventId != null && timelineEvents.find(event.eventId) != null) { return @@ -124,7 +124,7 @@ internal fun ChunkEntity.add(roomId: String, backwardsDisplayIndex = currentDisplayIndex } var currentStateIndex = lastStateIndex(direction, defaultValue = stateIndexOffset) - if (direction == PaginationDirection.FORWARDS && EventType.isStateEvent(event.getClearType())) { + if (direction == PaginationDirection.FORWARDS && EventType.isStateEvent(event.type)) { currentStateIndex += 1 forwardsStateIndex = currentStateIndex } else if (direction == PaginationDirection.BACKWARDS && timelineEvents.isNotEmpty()) { @@ -157,7 +157,6 @@ internal fun ChunkEntity.add(roomId: String, } } - val eventEntity = TimelineEventEntity(localId).also { it.root = event.toEntity(roomId).apply { this.stateIndex = currentStateIndex @@ -169,6 +168,7 @@ internal fun ChunkEntity.add(roomId: String, it.roomId = roomId it.annotations = EventAnnotationsSummaryEntity.where(realm, eventId).findFirst() it.readReceipts = readReceiptsSummaryEntity + it.readMarker = ReadMarkerEntity.where(realm, roomId = roomId, eventId = eventId).findFirst() } val position = if (direction == PaginationDirection.FORWARDS) 0 else this.timelineEvents.size timelineEvents.add(position, eventEntity) @@ -186,4 +186,4 @@ internal fun ChunkEntity.lastStateIndex(direction: PaginationDirection, defaultV PaginationDirection.FORWARDS -> forwardsStateIndex PaginationDirection.BACKWARDS -> backwardsStateIndex } ?: defaultValue -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/TimelineEventEntityHelper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/TimelineEventEntityHelper.kt index f6bf258baa..24765c120d 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/TimelineEventEntityHelper.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/TimelineEventEntityHelper.kt @@ -30,7 +30,6 @@ import io.realm.Realm import io.realm.RealmList import io.realm.RealmQuery - internal fun TimelineEventEntity.updateSenderData() { assertIsManaged() val roomEntity = RoomEntity.where(realm, roomId = roomId).findFirst() ?: return @@ -67,7 +66,7 @@ internal fun TimelineEventEntity.updateSenderData() { this.senderMembershipEvent = senderMembershipEvent } -internal fun TimelineEventEntity.Companion.nextId(realm: Realm): Long{ +internal fun TimelineEventEntity.Companion.nextId(realm: Realm): Long { val currentIdNum = realm.where(TimelineEventEntity::class.java).max(TimelineEventEntityFields.LOCAL_ID) return if (currentIdNum == null) { 1 @@ -82,4 +81,3 @@ private fun RealmList.buildQuery(sender: String, isUnlinked .equalTo(TimelineEventEntityFields.ROOT.TYPE, EventType.STATE_ROOM_MEMBER) .equalTo(TimelineEventEntityFields.ROOT.IS_UNLINKED, isUnlinked) } - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/ContentMapper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/ContentMapper.kt index 801fdf3920..2406027f24 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/ContentMapper.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/ContentMapper.kt @@ -36,5 +36,4 @@ internal object ContentMapper { adapter.toJson(it) } } - } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/DraftMapper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/DraftMapper.kt index 6b87951e0a..3bd6cf14e4 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/DraftMapper.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/DraftMapper.kt @@ -42,4 +42,4 @@ internal object DraftMapper { is UserDraft.REPLY -> DraftEntity(content = domain.text, draftMode = DraftEntity.MODE_REPLY, linkedEventId = domain.linkedEventId) } } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/EventAnnotationsSummaryMapper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/EventAnnotationsSummaryMapper.kt index 1b7b7f6407..701d35926a 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/EventAnnotationsSummaryMapper.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/EventAnnotationsSummaryMapper.kt @@ -61,7 +61,7 @@ internal object EventAnnotationsSummaryMapper { it.lastEditTs ) } - eventAnnotationsSummaryEntity.reactionsSummary = annotationsSummary.reactionsSummary?.let { + eventAnnotationsSummaryEntity.reactionsSummary = annotationsSummary.reactionsSummary.let { RealmList().apply { addAll(it.map { ReactionAggregatedSummaryEntity( @@ -81,4 +81,4 @@ internal object EventAnnotationsSummaryMapper { internal fun EventAnnotationsSummaryEntity.asDomain(): EventAnnotationsSummary { return EventAnnotationsSummaryMapper.map(this) -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/EventMapper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/EventMapper.kt index 4375a19d17..ed5f04ef75 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/EventMapper.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/EventMapper.kt @@ -27,7 +27,6 @@ import timber.log.Timber internal object EventMapper { - fun map(event: Event, roomId: String): EventEntity { val uds = if (event.unsignedData == null) null else MoshiProvider.providesMoshi().adapter(UnsignedData::class.java).toJson(event.unsignedData) @@ -38,7 +37,7 @@ internal object EventMapper { val resolvedPrevContent = event.prevContent ?: event.unsignedData?.prevContent eventEntity.prevContent = ContentMapper.map(resolvedPrevContent) eventEntity.stateKey = event.stateKey - eventEntity.type = event.getClearType() + eventEntity.type = event.type eventEntity.sender = event.senderId eventEntity.originServerTs = event.originServerTs eventEntity.redacts = event.redacts @@ -48,16 +47,17 @@ internal object EventMapper { } fun map(eventEntity: EventEntity): Event { - val ud = if (eventEntity.unsignedData.isNullOrBlank()) { - null - } else { - try { - MoshiProvider.providesMoshi().adapter(UnsignedData::class.java).fromJson(eventEntity.unsignedData) - } catch (t: JsonDataException) { - null - } + val ud = eventEntity.unsignedData + ?.takeIf { it.isNotBlank() } + ?.let { + try { + MoshiProvider.providesMoshi().adapter(UnsignedData::class.java).fromJson(it) + } catch (t: JsonDataException) { + Timber.e(t, "Failed to parse UnsignedData") + null + } + } - } return Event( type = eventEntity.type, eventId = eventEntity.eventId, @@ -78,11 +78,12 @@ internal object EventMapper { Timber.e(t, "Failed to parse decryption result") } } - //TODO get the full crypto error object - it.mCryptoError = eventEntity.decryptionErrorCode?.let { MXCryptoError.ErrorType.valueOf(it) } + // TODO get the full crypto error object + it.mCryptoError = eventEntity.decryptionErrorCode?.let { errorCode -> + MXCryptoError.ErrorType.valueOf(errorCode) + } } } - } internal fun EventEntity.asDomain(): Event { @@ -92,4 +93,3 @@ internal fun EventEntity.asDomain(): Event { internal fun Event.toEntity(roomId: String): EventEntity { return EventMapper.map(this, roomId) } - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/GroupMapper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/GroupMapper.kt index fdd65be6b9..89ed5844c2 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/GroupMapper.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/GroupMapper.kt @@ -20,7 +20,6 @@ import im.vector.matrix.android.api.session.group.Group import im.vector.matrix.android.internal.database.model.GroupEntity import im.vector.matrix.android.internal.session.group.DefaultGroup - internal object GroupMapper { fun map(groupEntity: GroupEntity): Group { @@ -32,4 +31,4 @@ internal object GroupMapper { internal fun GroupEntity.asDomain(): Group { return GroupMapper.map(this) -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/GroupSummaryMapper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/GroupSummaryMapper.kt index 44cbf2998d..52e4d61d40 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/GroupSummaryMapper.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/GroupSummaryMapper.kt @@ -19,7 +19,6 @@ package im.vector.matrix.android.internal.database.mapper import im.vector.matrix.android.api.session.group.model.GroupSummary import im.vector.matrix.android.internal.database.model.GroupSummaryEntity - internal object GroupSummaryMapper { fun map(groupSummaryEntity: GroupSummaryEntity): GroupSummary { @@ -37,4 +36,4 @@ internal object GroupSummaryMapper { internal fun GroupSummaryEntity.asDomain(): GroupSummary { return GroupSummaryMapper.map(this) -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/HomeServerCapabilitiesMapper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/HomeServerCapabilitiesMapper.kt new file mode 100644 index 0000000000..66b0f1b379 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/HomeServerCapabilitiesMapper.kt @@ -0,0 +1,38 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.matrix.android.internal.database.mapper + +import im.vector.matrix.android.api.session.homeserver.HomeServerCapabilities +import im.vector.matrix.android.internal.database.model.HomeServerCapabilitiesEntity + +/** + * HomeServerCapabilitiesEntity <-> HomeSeverCapabilities + */ +internal object HomeServerCapabilitiesMapper { + + fun map(entity: HomeServerCapabilitiesEntity): HomeServerCapabilities { + return HomeServerCapabilities( + maxUploadFileSize = entity.maxUploadFileSize + ) + } + + fun map(domain: HomeServerCapabilities): HomeServerCapabilitiesEntity { + return HomeServerCapabilitiesEntity( + maxUploadFileSize = domain.maxUploadFileSize + ) + } +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/PushConditionMapper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/PushConditionMapper.kt index 4aabc9a8f1..3bc532fd93 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/PushConditionMapper.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/PushConditionMapper.kt @@ -19,7 +19,6 @@ package im.vector.matrix.android.internal.database.mapper import im.vector.matrix.android.api.pushrules.rest.PushCondition import im.vector.matrix.android.internal.database.model.PushConditionEntity - internal object PushConditionMapper { fun map(entity: PushConditionEntity): PushCondition { @@ -39,4 +38,4 @@ internal object PushConditionMapper { pattern = domain.pattern ) } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/PushRulesMapper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/PushRulesMapper.kt index 1ed2151e68..8912928a88 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/PushRulesMapper.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/PushRulesMapper.kt @@ -24,7 +24,6 @@ import im.vector.matrix.android.internal.di.MoshiProvider import io.realm.RealmList import timber.log.Timber - internal object PushRulesMapper { private val moshiActionsAdapter = MoshiProvider.providesMoshi().adapter>(Types.newParameterizedType(List::class.java, Any::class.java)) @@ -53,7 +52,6 @@ internal object PushRulesMapper { } } - fun mapRoomRule(pushrule: PushRuleEntity): PushRule { return PushRule( actions = fromActionStr(pushrule.actionsStr), @@ -78,7 +76,6 @@ internal object PushRulesMapper { ) } - fun map(pushrule: PushRuleEntity): PushRule { return PushRule( actions = fromActionStr(pushrule.actionsStr), @@ -101,5 +98,4 @@ internal object PushRulesMapper { } ?: RealmList() ) } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/PushersMapper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/PushersMapper.kt index d11532c588..315c8a766c 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/PushersMapper.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/PushersMapper.kt @@ -24,7 +24,6 @@ import im.vector.matrix.android.internal.session.pushers.JsonPusher internal object PushersMapper { fun map(pushEntity: PusherEntity): Pusher { - return Pusher( pushKey = pushEntity.pushKey, kind = pushEntity.kind ?: "", @@ -58,4 +57,4 @@ internal fun PusherEntity.asDomain(): Pusher { internal fun JsonPusher.toEntity(): PusherEntity { return PushersMapper.map(this) -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/ReadReceiptsSummaryMapper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/ReadReceiptsSummaryMapper.kt index 9fa9fc011d..952dfb9728 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/ReadReceiptsSummaryMapper.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/ReadReceiptsSummaryMapper.kt @@ -41,5 +41,4 @@ internal class ReadReceiptsSummaryMapper @Inject constructor(@SessionDatabase pr } } } - } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/RoomSummaryMapper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/RoomSummaryMapper.kt index 4fbe7fe04c..5db062b000 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/RoomSummaryMapper.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/RoomSummaryMapper.kt @@ -39,8 +39,8 @@ internal class RoomSummaryMapper @Inject constructor( timelineEventMapper.map(it) } if (latestEvent?.root?.isEncrypted() == true && latestEvent.root.mxDecryptionResult == null) { - //TODO use a global event decryptor? attache to session and that listen to new sessionId? - //for now decrypt sync + // TODO use a global event decryptor? attache to session and that listen to new sessionId? + // for now decrypt sync try { val result = cryptoService.decryptEvent(latestEvent.root, latestEvent.root.roomId + UUID.randomUUID().toString()) latestEvent.root.mxDecryptionResult = OlmDecryptionResult( @@ -50,7 +50,6 @@ internal class RoomSummaryMapper @Inject constructor( forwardingCurve25519KeyChain = result.forwardingCurve25519KeyChain ) } catch (e: MXCryptoError) { - } } @@ -68,6 +67,7 @@ internal class RoomSummaryMapper @Inject constructor( tags = tags, membership = roomSummaryEntity.membership, versioningState = roomSummaryEntity.versioningState, + readMarkerId = roomSummaryEntity.readMarkerId, userDrafts = roomSummaryEntity.userDrafts?.userDrafts?.map { DraftMapper.map(it) } ?: emptyList() ) } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/TimelineEventMapper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/TimelineEventMapper.kt index fe98ebfb5b..8046ecbff0 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/TimelineEventMapper.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/TimelineEventMapper.kt @@ -45,10 +45,8 @@ internal class TimelineEventMapper @Inject constructor(private val readReceiptsS senderAvatar = timelineEventEntity.senderAvatar, readReceipts = readReceipts?.sortedByDescending { it.originServerTs - } ?: emptyList() + } ?: emptyList(), + hasReadMarker = timelineEventEntity.readMarker?.eventId?.isNotEmpty() == true ) } - } - - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/UserMapper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/UserMapper.kt index 2389427c90..bfbe40df03 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/UserMapper.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/UserMapper.kt @@ -32,4 +32,4 @@ internal object UserMapper { internal fun UserEntity.asDomain(): User { return UserMapper.map(this) -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/ChunkEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/ChunkEntity.kt index d8661984d7..577c391b3a 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/ChunkEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/ChunkEntity.kt @@ -33,10 +33,10 @@ internal open class ChunkEntity(@Index var prevToken: String? = null, var forwardsStateIndex: Int? = null ) : RealmObject() { - fun identifier() = "${prevToken}_${nextToken}" + fun identifier() = "${prevToken}_$nextToken" @LinkingObjects("chunks") val room: RealmResults? = null companion object -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/DraftEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/DraftEntity.kt index 9666ebd9a1..3b5aae8b13 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/DraftEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/DraftEntity.kt @@ -31,4 +31,3 @@ internal open class DraftEntity(var content: String = "", const val MODE_QUOTE = "QUOTE" } } - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/EditAggregatedSummaryEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/EditAggregatedSummaryEntity.kt index f2690c96de..3a179eb1f0 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/EditAggregatedSummaryEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/EditAggregatedSummaryEntity.kt @@ -30,5 +30,4 @@ internal open class EditAggregatedSummaryEntity( ) : RealmObject() { companion object - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/EventAnnotationsSummaryEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/EventAnnotationsSummaryEntity.kt index 4c6b26f0e5..523d94b770 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/EventAnnotationsSummaryEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/EventAnnotationsSummaryEntity.kt @@ -19,7 +19,6 @@ import io.realm.RealmList import io.realm.RealmObject import io.realm.annotations.PrimaryKey - internal open class EventAnnotationsSummaryEntity( @PrimaryKey var eventId: String = "", @@ -29,5 +28,4 @@ internal open class EventAnnotationsSummaryEntity( ) : RealmObject() { companion object - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/EventEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/EventEntity.kt index 4401d394bb..4def7aec5d 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/EventEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/EventEntity.kt @@ -59,7 +59,6 @@ internal open class EventEntity(@Index var eventId: String = "", sendStateStr = value.name } - companion object @LinkingObjects("untimelinedStateEvents") @@ -68,7 +67,6 @@ internal open class EventEntity(@Index var eventId: String = "", @LinkingObjects("root") val timelineEventEntity: RealmResults? = null - fun setDecryptionResult(result: MXEventDecryptionResult) { val decryptionResult = OlmDecryptionResult( payload = result.clearEvent, @@ -81,4 +79,4 @@ internal open class EventEntity(@Index var eventId: String = "", decryptionErrorCode = null timelineEventEntity?.firstOrNull()?.root = this } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/FilterEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/FilterEntity.kt index 13209cb96e..eabcdce34d 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/FilterEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/FilterEntity.kt @@ -33,4 +33,4 @@ internal open class FilterEntity( ) : RealmObject() { companion object -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/GroupEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/GroupEntity.kt index 433f209501..eb346a74ca 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/GroupEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/GroupEntity.kt @@ -38,5 +38,4 @@ internal open class GroupEntity(@PrimaryKey var groupId: String = "") } companion object - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/GroupSummaryEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/GroupSummaryEntity.kt index 7ab67b6ab0..f3700b1dd7 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/GroupSummaryEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/GroupSummaryEntity.kt @@ -39,5 +39,4 @@ internal open class GroupSummaryEntity(@PrimaryKey var groupId: String = "", } companion object - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/HomeServerCapabilitiesEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/HomeServerCapabilitiesEntity.kt new file mode 100644 index 0000000000..0d067286e1 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/HomeServerCapabilitiesEntity.kt @@ -0,0 +1,28 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.matrix.android.internal.database.model + +import im.vector.matrix.android.api.session.homeserver.HomeServerCapabilities +import io.realm.RealmObject + +internal open class HomeServerCapabilitiesEntity( + var maxUploadFileSize: Long = HomeServerCapabilities.MAX_UPLOAD_FILE_SIZE_UNKNOWN, + var lastUpdatedTimestamp: Long = 0L +) : RealmObject() { + + companion object +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/PushConditionEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/PushConditionEntity.kt index e6c3d406c8..7922db5c0a 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/PushConditionEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/PushConditionEntity.kt @@ -25,5 +25,4 @@ internal open class PushConditionEntity( ) : RealmObject() { companion object - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/PushRuleEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/PushRuleEntity.kt index dd6cc79022..4744c8d053 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/PushRuleEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/PushRuleEntity.kt @@ -19,21 +19,19 @@ import io.realm.RealmList import io.realm.RealmObject internal open class PushRuleEntity( - //Required. The actions to perform when this rule is matched. + // Required. The actions to perform when this rule is matched. var actionsStr: String? = null, - //Required. Whether this is a default rule, or has been set explicitly. + // Required. Whether this is a default rule, or has been set explicitly. var default: Boolean = false, - //Required. Whether the push rule is enabled or not. + // Required. Whether the push rule is enabled or not. var enabled: Boolean = true, - //Required. The ID of this rule. + // Required. The ID of this rule. var ruleId: String = "", - //The conditions that must hold true for an event in order for a rule to be applied to an event + // The conditions that must hold true for an event in order for a rule to be applied to an event var conditions: RealmList? = RealmList(), - //The glob-style pattern to match against. Only applicable to content rules. + // The glob-style pattern to match against. Only applicable to content rules. var pattern: String? = null ) : RealmObject() { companion object - } - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/PushRulesEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/PushRulesEntity.kt index e0acfa49ae..9527dafba4 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/PushRulesEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/PushRulesEntity.kt @@ -19,7 +19,6 @@ import im.vector.matrix.android.api.pushrules.RuleKind import io.realm.RealmList import io.realm.RealmObject - internal open class PushRulesEntity( var scope: String = "", var pushRules: RealmList = RealmList() @@ -35,4 +34,4 @@ internal open class PushRulesEntity( } companion object -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/PusherDataEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/PusherDataEntity.kt index 87694fb723..acc4f43bf9 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/PusherDataEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/PusherDataEntity.kt @@ -22,4 +22,4 @@ internal open class PusherDataEntity( var format: String? = null ) : RealmObject() { companion object -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/PusherEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/PusherEntity.kt index 6ec9d4b0de..9c4dcce3cd 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/PusherEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/PusherEntity.kt @@ -18,7 +18,7 @@ package im.vector.matrix.android.internal.database.model import im.vector.matrix.android.api.session.pushers.PusherState import io.realm.RealmObject -//TODO +// TODO // at java.lang.Thread.run(Thread.java:764) // Caused by: java.lang.IllegalArgumentException: 'value' is not a valid managed object. // at io.realm.ProxyState.checkValidObject(ProxyState.java:213) @@ -44,14 +44,13 @@ internal open class PusherEntity( try { return PusherState.valueOf(stateStr) } catch (e: Exception) { - //can this happen? + // can this happen? return PusherState.UNREGISTERED } - } set(value) { stateStr = value.name } companion object -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/ReactionAggregatedSummaryEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/ReactionAggregatedSummaryEntity.kt index 70938e5b89..58da4faf6b 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/ReactionAggregatedSummaryEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/ReactionAggregatedSummaryEntity.kt @@ -38,5 +38,4 @@ internal open class ReactionAggregatedSummaryEntity( ) : RealmObject() { companion object - } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/ReadMarkerEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/ReadMarkerEntity.kt new file mode 100644 index 0000000000..9e78c94f88 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/ReadMarkerEntity.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.matrix.android.internal.database.model + +import io.realm.RealmObject +import io.realm.RealmResults +import io.realm.annotations.LinkingObjects +import io.realm.annotations.PrimaryKey + +internal open class ReadMarkerEntity( + @PrimaryKey + var roomId: String = "", + var eventId: String = "" +) : RealmObject() { + + @LinkingObjects("readMarker") + val timelineEvent: RealmResults? = null + + companion object +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/ReadReceiptsSummaryEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/ReadReceiptsSummaryEntity.kt index 56e8938caa..b08ed0f728 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/ReadReceiptsSummaryEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/ReadReceiptsSummaryEntity.kt @@ -33,5 +33,4 @@ internal open class ReadReceiptsSummaryEntity( val timelineEvent: RealmResults? = null companion object - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/RoomEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/RoomEntity.kt index a9f91390be..7de9451c32 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/RoomEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/RoomEntity.kt @@ -39,4 +39,3 @@ internal open class RoomEntity(@PrimaryKey var roomId: String = "", companion object } - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/RoomSummaryEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/RoomSummaryEntity.kt index 1c159b23d2..f414325aed 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/RoomSummaryEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/RoomSummaryEntity.kt @@ -35,6 +35,7 @@ internal open class RoomSummaryEntity(@PrimaryKey var roomId: String = "", var otherMemberIds: RealmList = RealmList(), var notificationCount: Int = 0, var highlightCount: Int = 0, + var readMarkerId: String? = null, var hasUnreadMessages: Boolean = false, var tags: RealmList = RealmList(), var userDrafts: UserDraftsEntity? = null @@ -59,5 +60,4 @@ internal open class RoomSummaryEntity(@PrimaryKey var roomId: String = "", } companion object - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/RoomTagEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/RoomTagEntity.kt index 12ca29b179..c78aa6ae84 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/RoomTagEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/RoomTagEntity.kt @@ -24,5 +24,4 @@ internal open class RoomTagEntity( ) : RealmObject() { companion object - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/SessionRealmModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/SessionRealmModule.kt index 680e2eac7d..21b2fdce5a 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/SessionRealmModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/SessionRealmModule.kt @@ -44,7 +44,9 @@ import io.realm.annotations.RealmModule PusherEntity::class, PusherDataEntity::class, ReadReceiptsSummaryEntity::class, + ReadMarkerEntity::class, UserDraftsEntity::class, - DraftEntity::class + DraftEntity::class, + HomeServerCapabilitiesEntity::class ]) internal class SessionRealmModule diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/SyncEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/SyncEntity.kt index a7d3db1a7b..2eb39be325 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/SyncEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/SyncEntity.kt @@ -21,4 +21,4 @@ import io.realm.annotations.PrimaryKey internal open class SyncEntity(var nextBatch: String? = null, @PrimaryKey var id: Long = 0 -) : RealmObject() \ No newline at end of file +) : RealmObject() diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/TimelineEventEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/TimelineEventEntity.kt index 429b2291f6..fd3a427781 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/TimelineEventEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/TimelineEventEntity.kt @@ -21,7 +21,6 @@ import io.realm.RealmResults import io.realm.annotations.Index import io.realm.annotations.LinkingObjects - internal open class TimelineEventEntity(var localId: Long = 0, @Index var eventId: String = "", @Index var roomId: String = "", @@ -31,12 +30,12 @@ internal open class TimelineEventEntity(var localId: Long = 0, var isUniqueDisplayName: Boolean = false, var senderAvatar: String? = null, var senderMembershipEvent: EventEntity? = null, - var readReceipts: ReadReceiptsSummaryEntity? = null + var readReceipts: ReadReceiptsSummaryEntity? = null, + var readMarker: ReadMarkerEntity? = null ) : RealmObject() { @LinkingObjects("timelineEvents") val chunk: RealmResults? = null companion object - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/UserDraftsEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/UserDraftsEntity.kt index b713fe1c3f..432b3367ad 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/UserDraftsEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/UserDraftsEntity.kt @@ -32,5 +32,4 @@ internal open class UserDraftsEntity(var userDrafts: RealmList = Re val roomSummaryEntity: RealmResults? = null companion object - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/UserEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/UserEntity.kt index b4bfd9f22b..baf7629fdc 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/UserEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/UserEntity.kt @@ -26,4 +26,3 @@ internal open class UserEntity(@PrimaryKey var userId: String = "", companion object } - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/ChunkEntityQueries.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/ChunkEntityQueries.kt index 2f7145629a..69402ac1de 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/ChunkEntityQueries.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/ChunkEntityQueries.kt @@ -62,4 +62,4 @@ internal fun ChunkEntity.Companion.create(realm: Realm, prevToken: String?, next this.prevToken = prevToken this.nextToken = nextToken } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/EventAnnotationsSummaryEntityQuery.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/EventAnnotationsSummaryEntityQuery.kt index f1179ebeb4..1e7a5758ad 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/EventAnnotationsSummaryEntityQuery.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/EventAnnotationsSummaryEntityQuery.kt @@ -37,12 +37,13 @@ internal fun EventAnnotationsSummaryEntity.Companion.whereInRoom(realm: Realm, r return query } - -internal fun EventAnnotationsSummaryEntity.Companion.create(realm: Realm, eventId: String): EventAnnotationsSummaryEntity { - val obj = realm.createObject(EventAnnotationsSummaryEntity::class.java, eventId) - //Denormalization - TimelineEventEntity.where(realm, eventId = eventId).findFirst()?.let { +internal fun EventAnnotationsSummaryEntity.Companion.create(realm: Realm, roomId: String, eventId: String): EventAnnotationsSummaryEntity { + val obj = realm.createObject(EventAnnotationsSummaryEntity::class.java, eventId).apply { + this.roomId = roomId + } + // Denormalization + TimelineEventEntity.where(realm, roomId = roomId, eventId = eventId).findFirst()?.let { it.annotations = obj } return obj -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/EventEntityQueries.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/EventEntityQueries.kt index 6610edb884..62f53c3d7b 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/EventEntityQueries.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/EventEntityQueries.kt @@ -53,7 +53,6 @@ internal fun EventEntity.Companion.where(realm: Realm, } } - internal fun EventEntity.Companion.types(realm: Realm, typeList: List = emptyList()): RealmQuery { val query = realm.where() diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/FilterContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/FilterContent.kt index 92608a1f42..be7075ddd0 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/FilterContent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/FilterContent.kt @@ -19,5 +19,4 @@ package im.vector.matrix.android.internal.database.query internal object FilterContent { internal const val EDIT_TYPE = """{*"m.relates_to"*"rel_type":*"m.replace"*}""" - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/HomeServerCapabilitiesQueries.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/HomeServerCapabilitiesQueries.kt new file mode 100644 index 0000000000..e7002a9005 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/HomeServerCapabilitiesQueries.kt @@ -0,0 +1,36 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.matrix.android.internal.database.query + +import im.vector.matrix.android.internal.database.model.HomeServerCapabilitiesEntity +import io.realm.Realm +import io.realm.kotlin.createObject +import io.realm.kotlin.where + +/** + * Get the current HomeServerCapabilitiesEntity, return null if it does not exist + */ +internal fun HomeServerCapabilitiesEntity.Companion.get(realm: Realm): HomeServerCapabilitiesEntity? { + return realm.where().findFirst() +} + +/** + * Get the current HomeServerCapabilitiesEntity, create one if it does not exist + */ +internal fun HomeServerCapabilitiesEntity.Companion.getOrCreate(realm: Realm): HomeServerCapabilitiesEntity { + return get(realm) ?: realm.createObject() +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/ReadMarkerEntityQueries.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/ReadMarkerEntityQueries.kt new file mode 100644 index 0000000000..061634a9da --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/ReadMarkerEntityQueries.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.matrix.android.internal.database.query + +import im.vector.matrix.android.internal.database.model.ReadMarkerEntity +import im.vector.matrix.android.internal.database.model.ReadMarkerEntityFields +import io.realm.Realm +import io.realm.RealmQuery +import io.realm.kotlin.where + +internal fun ReadMarkerEntity.Companion.where(realm: Realm, roomId: String, eventId: String? = null): RealmQuery { + val query = realm.where() + .equalTo(ReadMarkerEntityFields.ROOM_ID, roomId) + if (eventId != null) { + query.equalTo(ReadMarkerEntityFields.EVENT_ID, eventId) + } + return query +} + +internal fun ReadMarkerEntity.Companion.getOrCreate(realm: Realm, roomId: String): ReadMarkerEntity { + return where(realm, roomId).findFirst() + ?: realm.createObject(ReadMarkerEntity::class.java, roomId) +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/ReadQueries.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/ReadQueries.kt index bd7e3a7a5e..0a925ac1ab 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/ReadQueries.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/ReadQueries.kt @@ -16,6 +16,7 @@ package im.vector.matrix.android.internal.database.query import com.zhuinden.monarchy.Monarchy +import im.vector.matrix.android.api.session.events.model.LocalEcho import im.vector.matrix.android.internal.database.model.ChunkEntity import im.vector.matrix.android.internal.database.model.ReadReceiptEntity @@ -26,7 +27,9 @@ internal fun isEventRead(monarchy: Monarchy, if (userId.isNullOrBlank() || roomId.isNullOrBlank() || eventId.isNullOrBlank()) { return false } - + if (LocalEcho.isLocalEchoId(eventId)) { + return true + } var isEventRead = false monarchy.doWithRealm { realm -> @@ -45,4 +48,4 @@ internal fun isEventRead(monarchy: Monarchy, } return isEventRead -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/ReadReceiptEntityQueries.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/ReadReceiptEntityQueries.kt index acac419946..e0a507f939 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/ReadReceiptEntityQueries.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/ReadReceiptEntityQueries.kt @@ -28,6 +28,11 @@ internal fun ReadReceiptEntity.Companion.where(realm: Realm, roomId: String, use .equalTo(ReadReceiptEntityFields.USER_ID, userId) } +internal fun ReadReceiptEntity.Companion.whereUserId(realm: Realm, userId: String): RealmQuery { + return realm.where() + .equalTo(ReadReceiptEntityFields.USER_ID, userId) +} + internal fun ReadReceiptEntity.Companion.createUnmanaged(roomId: String, eventId: String, userId: String, originServerTs: Double): ReadReceiptEntity { return ReadReceiptEntity().apply { this.primaryKey = "${roomId}_$userId" diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/ReadReceiptsSummaryEntityQueries.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/ReadReceiptsSummaryEntityQueries.kt index 0c3d7d8eb1..1773297727 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/ReadReceiptsSummaryEntityQueries.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/ReadReceiptsSummaryEntityQueries.kt @@ -27,10 +27,7 @@ internal fun ReadReceiptsSummaryEntity.Companion.where(realm: Realm, eventId: St .equalTo(ReadReceiptsSummaryEntityFields.EVENT_ID, eventId) } -internal fun ReadReceiptsSummaryEntity.Companion.whereInRoom(realm: Realm, roomId: String?): RealmQuery { - val query = realm.where() - if (roomId != null) { - query.equalTo(ReadReceiptsSummaryEntityFields.ROOM_ID, roomId) - } - return query +internal fun ReadReceiptsSummaryEntity.Companion.whereInRoom(realm: Realm, roomId: String): RealmQuery { + return realm.where() + .equalTo(ReadReceiptsSummaryEntityFields.ROOM_ID, roomId) } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/RoomSummaryEntityQueries.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/RoomSummaryEntityQueries.kt index f2c260421f..a92d81b54c 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/RoomSummaryEntityQueries.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/RoomSummaryEntityQueries.kt @@ -31,6 +31,11 @@ internal fun RoomSummaryEntity.Companion.where(realm: Realm, roomId: String? = n return query } +internal fun RoomSummaryEntity.Companion.getOrCreate(realm: Realm, roomId: String): RoomSummaryEntity { + return where(realm, roomId).findFirst() + ?: realm.createObject(RoomSummaryEntity::class.java, roomId) +} + internal fun RoomSummaryEntity.Companion.getDirectRooms(realm: Realm): RealmResults { return RoomSummaryEntity.where(realm) .equalTo(RoomSummaryEntityFields.IS_DIRECT, true) @@ -44,6 +49,3 @@ internal fun RoomSummaryEntity.Companion.isDirect(realm: Realm, roomId: String): .findAll() .isNotEmpty() } - - - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/TimelineEventEntityQueries.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/TimelineEventEntityQueries.kt index 182e58a3b5..49474e8e6b 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/TimelineEventEntityQueries.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/TimelineEventEntityQueries.kt @@ -22,13 +22,15 @@ import im.vector.matrix.android.internal.database.model.EventEntity.LinkFilterMo import io.realm.* import io.realm.kotlin.where -internal fun TimelineEventEntity.Companion.where(realm: Realm, eventId: String): RealmQuery { +internal fun TimelineEventEntity.Companion.where(realm: Realm, roomId: String, eventId: String): RealmQuery { return realm.where() + .equalTo(TimelineEventEntityFields.ROOM_ID, roomId) .equalTo(TimelineEventEntityFields.EVENT_ID, eventId) } -internal fun TimelineEventEntity.Companion.where(realm: Realm, eventIds: List): RealmQuery { +internal fun TimelineEventEntity.Companion.where(realm: Realm, roomId: String, eventIds: List): RealmQuery { return realm.where() + .equalTo(TimelineEventEntityFields.ROOM_ID, roomId) .`in`(TimelineEventEntityFields.EVENT_ID, eventIds.toTypedArray()) } @@ -56,30 +58,31 @@ internal fun TimelineEventEntity.Companion.findWithSenderMembershipEvent(realm: .findAll() } - internal fun TimelineEventEntity.Companion.latestEvent(realm: Realm, roomId: String, includesSending: Boolean, - includedTypes: List = emptyList(), - excludedTypes: List = emptyList()): TimelineEventEntity? { - + filterTypes: List = emptyList()): TimelineEventEntity? { val roomEntity = RoomEntity.where(realm, roomId).findFirst() ?: return null - val eventList = if (includesSending && roomEntity.sendingTimelineEvents.isNotEmpty()) { - roomEntity.sendingTimelineEvents + val sendingTimelineEvents = roomEntity.sendingTimelineEvents.where().filterTypes(filterTypes) + val liveEvents = ChunkEntity.findLastLiveChunkFromRoom(realm, roomId)?.timelineEvents?.where()?.filterTypes(filterTypes) + val query = if (includesSending && sendingTimelineEvents.findAll().isNotEmpty()) { + sendingTimelineEvents } else { - ChunkEntity.findLastLiveChunkFromRoom(realm, roomId)?.timelineEvents - } - val query = eventList?.where() - if (includedTypes.isNotEmpty()) { - query?.`in`(TimelineEventEntityFields.ROOT.TYPE, includedTypes.toTypedArray()) - } else if (excludedTypes.isNotEmpty()) { - query?.not()?.`in`(TimelineEventEntityFields.ROOT.TYPE, excludedTypes.toTypedArray()) + liveEvents } return query ?.sort(TimelineEventEntityFields.ROOT.DISPLAY_INDEX, Sort.DESCENDING) ?.findFirst() } +internal fun RealmQuery.filterTypes(filterTypes: List): RealmQuery { + return if (filterTypes.isEmpty()) { + this + } else { + this.`in`(TimelineEventEntityFields.ROOT.TYPE, filterTypes.toTypedArray()) + } +} + internal fun RealmQuery.next(from: Int? = null, strict: Boolean = true): TimelineEventEntity? { if (from != null) { if (strict) { @@ -106,7 +109,6 @@ internal fun RealmQuery.prev(since: Int? = null, strict: Bo .findFirst() } - internal fun RealmList.find(eventId: String): TimelineEventEntity? { return this.where() .equalTo(TimelineEventEntityFields.ROOT.EVENT_ID, eventId) @@ -117,10 +119,9 @@ internal fun TimelineEventEntity.Companion.findAllInRoomWithSendStates(realm: Re roomId: String, sendStates: List) : RealmResults { - val sendStatesStr = sendStates.map { it.name }.toTypedArray() return realm.where() .equalTo(TimelineEventEntityFields.ROOM_ID, roomId) - .`in`(TimelineEventEntityFields.ROOT.SEND_STATE_STR,sendStatesStr) + .`in`(TimelineEventEntityFields.ROOT.SEND_STATE_STR, sendStatesStr) .findAll() -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/UserDraftsEntityQueries.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/UserDraftsEntityQueries.kt index ae368c5850..149efee492 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/UserDraftsEntityQueries.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/UserDraftsEntityQueries.kt @@ -30,4 +30,3 @@ internal fun UserDraftsEntity.Companion.where(realm: Realm, roomId: String? = nu } return query } - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/AuthQualifiers.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/AuthQualifiers.kt index 55f0c28c18..8ee27b3375 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/AuthQualifiers.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/AuthQualifiers.kt @@ -24,4 +24,4 @@ annotation class Authenticated @Qualifier @Retention(AnnotationRetention.RUNTIME) -annotation class Unauthenticated \ No newline at end of file +annotation class Unauthenticated diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/DbQualifiers.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/DbQualifiers.kt index ac9a30a3ec..3fdeb7eacc 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/DbQualifiers.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/DbQualifiers.kt @@ -28,4 +28,4 @@ annotation class SessionDatabase @Qualifier @Retention(AnnotationRetention.RUNTIME) -annotation class CryptoDatabase \ No newline at end of file +annotation class CryptoDatabase diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MatrixComponent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MatrixComponent.kt index 1627266c1c..f7314fe6b4 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MatrixComponent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MatrixComponent.kt @@ -33,7 +33,6 @@ import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers import okhttp3.OkHttpClient import org.matrix.olm.OlmManager - @Component(modules = [MatrixModule::class, NetworkModule::class, AuthModule::class]) @MatrixScope internal interface MatrixComponent { @@ -69,5 +68,4 @@ internal interface MatrixComponent { interface Factory { fun create(@BindsInstance context: Context): MatrixComponent } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MatrixModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MatrixModule.kt index 55b92ef89b..811950ac15 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MatrixModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MatrixModule.kt @@ -55,5 +55,4 @@ internal object MatrixModule { fun providesOlmManager(): OlmManager { return OlmManager() } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MatrixScope.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MatrixScope.kt index fadcdacf21..54e1467695 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MatrixScope.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MatrixScope.kt @@ -24,4 +24,4 @@ import javax.inject.Scope @Scope @MustBeDocumented @Retention(AnnotationRetention.RUNTIME) -annotation class MatrixScope \ No newline at end of file +internal annotation class MatrixScope diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MoshiProvider.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MoshiProvider.kt index 81de47948c..d8db462f7c 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MoshiProvider.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MoshiProvider.kt @@ -25,7 +25,6 @@ import im.vector.matrix.android.internal.session.sync.model.UserAccountDataDirec import im.vector.matrix.android.internal.session.sync.model.UserAccountDataFallback import im.vector.matrix.android.internal.session.sync.model.UserAccountDataPushRules - object MoshiProvider { private val moshi: Moshi = Moshi.Builder() @@ -50,7 +49,4 @@ object MoshiProvider { fun providesMoshi(): Moshi { return moshi } - } - - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/NetworkModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/NetworkModule.kt index 2061d03bed..4d6c66b7ed 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/NetworkModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/NetworkModule.kt @@ -92,4 +92,4 @@ internal object NetworkModule { fun providesMoshi(): Moshi { return MoshiProvider.providesMoshi() } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/SessionAssistedInjectModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/SessionAssistedInjectModule.kt index 1e8686da92..52100a598a 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/SessionAssistedInjectModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/SessionAssistedInjectModule.kt @@ -21,4 +21,4 @@ import dagger.Module @AssistedModule @Module(includes = [AssistedInject_SessionAssistedInjectModule::class]) -interface SessionAssistedInjectModule \ No newline at end of file +interface SessionAssistedInjectModule diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/UserCacheDirectory.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/UserCacheDirectory.kt new file mode 100644 index 0000000000..93df68ed07 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/UserCacheDirectory.kt @@ -0,0 +1,29 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Unfortunatly "ktlint-disable filename" this does not work so this file is renamed to UserCacheDirectory.kt + * If a new qualifier is added, please rename this file ti FileQualifiers.kt... + */ +/* ktlint-disable filename */ + +package im.vector.matrix.android.internal.di + +import javax.inject.Qualifier + +@Qualifier +@Retention(AnnotationRetention.RUNTIME) +annotation class UserCacheDirectory diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/extensions/RealmExtensions.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/extensions/RealmExtensions.kt index 4894538200..8934bdb0b6 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/extensions/RealmExtensions.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/extensions/RealmExtensions.kt @@ -19,7 +19,5 @@ package im.vector.matrix.android.internal.extensions import io.realm.RealmObject internal fun RealmObject.assertIsManaged() { - if (!isManaged) { - throw IllegalStateException("${javaClass.simpleName} entity should be managed to use this function") - } -} \ No newline at end of file + check(isManaged) { "${javaClass.simpleName} entity should be managed to use this function" } +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/extensions/Try.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/extensions/Try.kt index 7852940487..6a23ca9094 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/extensions/Try.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/extensions/Try.kt @@ -38,4 +38,4 @@ fun Try.foldToCallback(callback: MatrixCallback): Unit = fold( inline fun Try.alsoDo(f: (A) -> Unit) = map { f(it) it -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/AccessTokenInterceptor.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/AccessTokenInterceptor.kt index 70b16a4d61..2630560e45 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/AccessTokenInterceptor.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/AccessTokenInterceptor.kt @@ -31,6 +31,4 @@ internal class AccessTokenInterceptor @Inject constructor(private val credential request = newRequestBuilder.build() return chain.proceed(request) } - - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/HttpHeaders.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/HttpHeaders.kt index f4b93e8a31..11fafd5c5a 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/HttpHeaders.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/HttpHeaders.kt @@ -20,5 +20,4 @@ object HttpHeaders { const val Authorization = "Authorization" const val UserAgent = "User-Agent" - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/NetworkConnectivityChecker.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/NetworkConnectivityChecker.kt index be012dd308..bfc37d733d 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/NetworkConnectivityChecker.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/NetworkConnectivityChecker.kt @@ -101,14 +101,9 @@ internal class NetworkConnectivityChecker @Inject constructor(context: Context, interface Listener { fun onConnect() { - } fun onDisconnect() { - } } - - } - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/NetworkConstants.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/NetworkConstants.kt index cbd4d0c674..d0d8d134cb 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/NetworkConstants.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/NetworkConstants.kt @@ -22,4 +22,7 @@ internal object NetworkConstants { const val URI_API_PREFIX_PATH_R0 = "$URI_API_PREFIX_PATH/r0/" const val URI_API_PREFIX_PATH_UNSTABLE = "$URI_API_PREFIX_PATH/unstable/" + // Media + private const val URI_API_MEDIA_PREFIX_PATH = "_matrix/media" + const val URI_API_MEDIA_PREFIX_PATH_R0 = "$URI_API_MEDIA_PREFIX_PATH/r0/" } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/ProgressRequestBody.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/ProgressRequestBody.kt index 49655ab4df..6e371f7a5c 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/ProgressRequestBody.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/ProgressRequestBody.kt @@ -43,7 +43,7 @@ internal class ProgressRequestBody(private val delegate: RequestBody, @Throws(IOException::class) override fun writeTo(sink: BufferedSink) { countingSink = CountingSink(sink) - val bufferedSink = Okio.buffer(countingSink) + val bufferedSink = countingSink.buffer() delegate.writeTo(bufferedSink) bufferedSink.flush() } @@ -63,4 +63,4 @@ internal class ProgressRequestBody(private val delegate: RequestBody, interface Listener { fun onProgress(current: Long, total: Long) } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/Request.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/Request.kt index ede9e823bf..7f8e6643c3 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/Request.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/Request.kt @@ -16,24 +16,15 @@ package im.vector.matrix.android.internal.network -import com.squareup.moshi.JsonDataException -import com.squareup.moshi.Moshi -import im.vector.matrix.android.api.failure.ConsentNotGivenError import im.vector.matrix.android.api.failure.Failure -import im.vector.matrix.android.api.failure.MatrixError -import im.vector.matrix.android.internal.di.MoshiProvider import kotlinx.coroutines.CancellationException -import okhttp3.ResponseBody -import org.greenrobot.eventbus.EventBus import retrofit2.Call -import timber.log.Timber import java.io.IOException internal suspend inline fun executeRequest(block: Request.() -> Unit) = Request().apply(block).execute() internal class Request { - private val moshi: Moshi = MoshiProvider.providesMoshi() lateinit var apiCall: Call suspend fun execute(): DATA { @@ -43,7 +34,7 @@ internal class Request { response.body() ?: throw IllegalStateException("The request returned a null body") } else { - throw manageFailure(response.errorBody(), response.code()) + throw response.toFailure() } } catch (exception: Throwable) { throw when (exception) { @@ -55,32 +46,4 @@ internal class Request { } } } - - private fun manageFailure(errorBody: ResponseBody?, httpCode: Int): Throwable { - if (errorBody == null) { - return RuntimeException("Error body should not be null") - } - - val errorBodyStr = errorBody.string() - - val matrixErrorAdapter = moshi.adapter(MatrixError::class.java) - - try { - val matrixError = matrixErrorAdapter.fromJson(errorBodyStr) - - if (matrixError != null) { - if (matrixError.code == MatrixError.M_CONSENT_NOT_GIVEN && !matrixError.consentUri.isNullOrBlank()) { - // Also send this error to the bus, for a global management - EventBus.getDefault().post(ConsentNotGivenError(matrixError.consentUri)) - } - - return Failure.ServerError(matrixError, httpCode) - } - } catch (ex: JsonDataException) { - // This is not a MatrixError - Timber.w("The error returned by the server is not a MatrixError") - } - - return Failure.OtherServerError(errorBodyStr, httpCode) - } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/RetrofitExtensions.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/RetrofitExtensions.kt index 824d74b30e..29b20f9739 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/RetrofitExtensions.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/RetrofitExtensions.kt @@ -18,14 +18,23 @@ package im.vector.matrix.android.internal.network +import com.squareup.moshi.JsonDataException +import im.vector.matrix.android.api.failure.ConsentNotGivenError +import im.vector.matrix.android.api.failure.Failure +import im.vector.matrix.android.api.failure.MatrixError +import im.vector.matrix.android.internal.di.MoshiProvider import kotlinx.coroutines.suspendCancellableCoroutine +import okhttp3.ResponseBody +import org.greenrobot.eventbus.EventBus import retrofit2.Call import retrofit2.Callback import retrofit2.Response +import timber.log.Timber +import java.io.IOException import kotlin.coroutines.resume import kotlin.coroutines.resumeWithException -suspend fun Call.awaitResponse(): Response { +internal suspend fun Call.awaitResponse(): Response { return suspendCancellableCoroutine { continuation -> continuation.invokeOnCancellation { cancel() @@ -40,4 +49,64 @@ suspend fun Call.awaitResponse(): Response { } }) } -} \ No newline at end of file +} + +internal suspend fun okhttp3.Call.awaitResponse(): okhttp3.Response { + return suspendCancellableCoroutine { continuation -> + continuation.invokeOnCancellation { + cancel() + } + + enqueue(object : okhttp3.Callback { + override fun onResponse(call: okhttp3.Call, response: okhttp3.Response) { + continuation.resume(response) + } + + override fun onFailure(call: okhttp3.Call, e: IOException) { + continuation.resumeWithException(e) + } + }) + } +} + +/** + * Convert a retrofit Response to a Failure, and eventually parse errorBody to convert it to a MatrixError + */ +internal fun Response.toFailure(): Failure { + return toFailure(errorBody(), code()) +} + +/** + * Convert a okhttp3 Response to a Failure, and eventually parse errorBody to convert it to a MatrixError + */ +internal fun okhttp3.Response.toFailure(): Failure { + return toFailure(body, code) +} + +private fun toFailure(errorBody: ResponseBody?, httpCode: Int): Failure { + if (errorBody == null) { + return Failure.Unknown(RuntimeException("errorBody should not be null")) + } + + val errorBodyStr = errorBody.string() + + val matrixErrorAdapter = MoshiProvider.providesMoshi().adapter(MatrixError::class.java) + + try { + val matrixError = matrixErrorAdapter.fromJson(errorBodyStr) + + if (matrixError != null) { + if (matrixError.code == MatrixError.M_CONSENT_NOT_GIVEN && !matrixError.consentUri.isNullOrBlank()) { + // Also send this error to the bus, for a global management + EventBus.getDefault().post(ConsentNotGivenError(matrixError.consentUri)) + } + + return Failure.ServerError(matrixError, httpCode) + } + } catch (ex: JsonDataException) { + // This is not a MatrixError + Timber.w("The error returned by the server is not a MatrixError") + } + + return Failure.OtherServerError(errorBodyStr, httpCode) +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/RetrofitFactory.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/RetrofitFactory.kt index 70143f7cbf..15e6f76381 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/RetrofitFactory.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/RetrofitFactory.kt @@ -32,5 +32,4 @@ class RetrofitFactory @Inject constructor(private val moshi: Moshi) { .addConverterFactory(MoshiConverterFactory.create(moshi)) .build() } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/TimeOutInterceptor.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/TimeOutInterceptor.kt index eea437cb0e..5adb4e89f1 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/TimeOutInterceptor.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/TimeOutInterceptor.kt @@ -53,4 +53,4 @@ internal class TimeOutInterceptor @Inject constructor() : Interceptor { const val READ_TIMEOUT = "READ_TIMEOUT" const val WRITE_TIMEOUT = "WRITE_TIMEOUT" } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/UnitConverterFactory.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/UnitConverterFactory.kt index 74d9623a6f..945a064a74 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/UnitConverterFactory.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/UnitConverterFactory.kt @@ -32,4 +32,4 @@ object UnitConverterFactory : Converter.Factory() { value.close() } } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/UserAgentHolder.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/UserAgentHolder.kt index 5c344a0b11..89da02b275 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/UserAgentHolder.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/UserAgentHolder.kt @@ -17,7 +17,6 @@ package im.vector.matrix.android.internal.network import android.content.Context -import android.text.TextUtils import im.vector.matrix.android.BuildConfig import im.vector.matrix.android.internal.di.MatrixScope import timber.log.Timber @@ -33,7 +32,6 @@ internal class UserAgentHolder @Inject constructor(private val context: Context) setApplicationFlavor("NoFlavor") } - /** * Create an user agent with the application version. * Ex: RiotX/1.0.0 (Linux; U; Android 6.0.1; SM-A510F Build/MMB29; Flavour GPlay; MatrixAndroidSDK_X 1.0) @@ -58,13 +56,13 @@ internal class UserAgentHolder @Inject constructor(private val context: Context) appName = appPackageName } } catch (e: Exception) { - Timber.e(e, "## initUserAgent() : failed " + e.message) + Timber.e(e, "## initUserAgent() : failed") } - var systemUserAgent = System.getProperty("http.agent") + val systemUserAgent = System.getProperty("http.agent") // cannot retrieve the application version - if (TextUtils.isEmpty(appName) || TextUtils.isEmpty(appVersion)) { + if (appName.isEmpty() || appVersion.isEmpty()) { if (null == systemUserAgent) { userAgent = "Java" + System.getProperty("java.version") } @@ -83,4 +81,4 @@ internal class UserAgentHolder @Inject constructor(private val context: Context) "; MatrixAndroidSDK_X " + BuildConfig.VERSION_NAME + ")" } } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/UserAgentInterceptor.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/UserAgentInterceptor.kt index 44e3ddd10e..f4e51e6173 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/UserAgentInterceptor.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/UserAgentInterceptor.kt @@ -34,5 +34,4 @@ internal class UserAgentInterceptor @Inject constructor(private val userAgentHol request = newRequestBuilder.build() return chain.proceed(request) } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/parsing/UriMoshiAdapter.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/parsing/UriMoshiAdapter.kt index 77b9a92106..9223c12259 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/parsing/UriMoshiAdapter.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/parsing/UriMoshiAdapter.kt @@ -31,5 +31,4 @@ internal class UriMoshiAdapter { fun fromJson(uriString: String): Uri { return Uri.parse(uriString) } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/ssl/CertUtil.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/ssl/CertUtil.kt index 976cbde17d..501fed0bd4 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/ssl/CertUtil.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/ssl/CertUtil.kt @@ -104,11 +104,11 @@ internal object CertUtil { * Recursively checks the exception to see if it was caused by an * UnrecognizedCertificateException * - * @param e the throwable. + * @param root the throwable. * @return The UnrecognizedCertificateException if exists, else null. */ - fun getCertificateException(e: Throwable?): UnrecognizedCertificateException? { - var e = e + fun getCertificateException(root: Throwable?): UnrecognizedCertificateException? { + var e = root var i = 0 // Just in case there is a getCause loop while (e != null && i < 10) { if (e is UnrecognizedCertificateException) { @@ -140,7 +140,7 @@ internal object CertUtil { try { tf = TrustManagerFactory.getInstance("PKIX") } catch (e: Exception) { - Timber.e(e, "## newPinnedSSLSocketFactory() : TrustManagerFactory.getInstance failed " + e.message) + Timber.e(e, "## newPinnedSSLSocketFactory() : TrustManagerFactory.getInstance failed") } // it doesn't exist, use the default one. @@ -148,9 +148,8 @@ internal object CertUtil { try { tf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()) } catch (e: Exception) { - Timber.e(e, "## addRule : onBingRuleUpdateFailure failed " + e.message) + Timber.e(e, "## addRule : onBingRuleUpdateFailure failed") } - } tf!!.init(null as KeyStore?) @@ -181,7 +180,6 @@ internal object CertUtil { } catch (e: Exception) { throw RuntimeException(e) } - } /** @@ -202,7 +200,7 @@ internal object CertUtil { try { for (cert in session.peerCertificates) { for (allowedFingerprint in trustedFingerprints) { - if (allowedFingerprint != null && cert is X509Certificate && allowedFingerprint.matchesCert(cert)) { + if (cert is X509Certificate && allowedFingerprint.matchesCert(cert)) { return@HostnameVerifier true } } @@ -235,6 +233,7 @@ internal object CertUtil { builder.cipherSuites(*tlsCipherSuites.toTypedArray()) } + @Suppress("DEPRECATION") builder.supportsTlsExtensions(hsConfig.shouldAcceptTlsExtensions) val list = ArrayList() list.add(builder.build()) @@ -243,4 +242,4 @@ internal object CertUtil { } return list } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/ssl/Fingerprint.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/ssl/Fingerprint.kt index 6a0a8189ad..99c2eb9c72 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/ssl/Fingerprint.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/ssl/Fingerprint.kt @@ -80,5 +80,4 @@ data class Fingerprint( @Json(name = "sha-1") SHA1, @Json(name = "sha-256")SHA256 } - } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/ssl/PinnedTrustManager.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/ssl/PinnedTrustManager.kt index 2438114aa2..f3f9ecc562 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/ssl/PinnedTrustManager.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/ssl/PinnedTrustManager.kt @@ -31,54 +31,50 @@ import javax.net.ssl.X509TrustManager * @param 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 mFingerprints: List?, - private val mDefaultTrustManager: X509TrustManager?) : X509TrustManager { +internal class PinnedTrustManager(private val fingerprints: List?, + private val defaultTrustManager: X509TrustManager?) : X509TrustManager { @Throws(CertificateException::class) override fun checkClientTrusted(chain: Array, s: String) { try { - if (mDefaultTrustManager != null) { - mDefaultTrustManager.checkClientTrusted( - chain, s - ) + if (defaultTrustManager != null) { + defaultTrustManager.checkClientTrusted(chain, s) return } } catch (e: CertificateException) { // If there is an exception we fall back to checking fingerprints - if (mFingerprints == null || mFingerprints.isEmpty()) { + if (fingerprints == null || fingerprints.isEmpty()) { throw UnrecognizedCertificateException(chain[0], Fingerprint.newSha256Fingerprint(chain[0]), e.cause) } } - checkTrusted("client", chain) + checkTrusted(chain) } @Throws(CertificateException::class) override fun checkServerTrusted(chain: Array, s: String) { try { - if (mDefaultTrustManager != null) { - mDefaultTrustManager.checkServerTrusted( - chain, s - ) + if (defaultTrustManager != null) { + defaultTrustManager.checkServerTrusted(chain, s) return } } catch (e: CertificateException) { // If there is an exception we fall back to checking fingerprints - if (mFingerprints == null || mFingerprints.isEmpty()) { + if (fingerprints == null || fingerprints.isEmpty()) { throw UnrecognizedCertificateException(chain[0], Fingerprint.newSha256Fingerprint(chain[0]), e.cause) } } - checkTrusted("server", chain) + checkTrusted(chain) } @Throws(CertificateException::class) - private fun checkTrusted(type: String, chain: Array) { + private fun checkTrusted(chain: Array) { val cert = chain[0] var found = false - if (mFingerprints != null) { - for (allowedFingerprint in mFingerprints) { + if (fingerprints != null) { + for (allowedFingerprint in fingerprints) { if (allowedFingerprint.matchesCert(cert)) { found = true break diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/ssl/TLSSocketFactory.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/ssl/TLSSocketFactory.kt index 032ec2fb7e..9b6d16a4d7 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/ssl/TLSSocketFactory.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/ssl/TLSSocketFactory.kt @@ -37,7 +37,6 @@ import javax.net.ssl.TrustManager internal class TLSSocketFactory - /** * Constructor * @@ -57,7 +56,7 @@ constructor(trustPinned: Array, acceptedTlsVersions: List reportSubtask(reporter: DefaultInitialSyncProgressService?, } } - inline fun Map.mapWithProgress(reporter: DefaultInitialSyncProgressService?, taskId: Int, weight: Float, @@ -139,4 +136,3 @@ inline fun Map.mapWithProgress(reporter: DefaultInitialSyncP reporter?.endTask(taskId) } } - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/DefaultSession.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/DefaultSession.kt index 02addaceab..4b33e28000 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/DefaultSession.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/DefaultSession.kt @@ -23,6 +23,7 @@ import androidx.lifecycle.LiveData import dagger.Lazy import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.auth.data.SessionParams +import im.vector.matrix.android.api.failure.ConsentNotGivenError import im.vector.matrix.android.api.pushrules.PushRuleService import im.vector.matrix.android.api.session.InitialSyncProgressService import im.vector.matrix.android.api.session.Session @@ -32,6 +33,7 @@ import im.vector.matrix.android.api.session.content.ContentUrlResolver import im.vector.matrix.android.api.session.crypto.CryptoService import im.vector.matrix.android.api.session.file.FileService import im.vector.matrix.android.api.session.group.GroupService +import im.vector.matrix.android.api.session.homeserver.HomeServerCapabilitiesService import im.vector.matrix.android.api.session.pushers.PushersService import im.vector.matrix.android.api.session.room.RoomDirectoryService import im.vector.matrix.android.api.session.room.RoomService @@ -44,6 +46,9 @@ import im.vector.matrix.android.internal.crypto.DefaultCryptoService import im.vector.matrix.android.internal.database.LiveEntityObserver import im.vector.matrix.android.internal.session.sync.job.SyncThread import im.vector.matrix.android.internal.session.sync.job.SyncWorker +import org.greenrobot.eventbus.EventBus +import org.greenrobot.eventbus.Subscribe +import org.greenrobot.eventbus.ThreadMode import timber.log.Timber import javax.inject.Inject import javax.inject.Provider @@ -68,7 +73,8 @@ internal class DefaultSession @Inject constructor(override val sessionParams: Se private val syncThreadProvider: Provider, private val contentUrlResolver: ContentUrlResolver, private val contentUploadProgressTracker: ContentUploadStateTracker, - private val initialSyncProgressService: Lazy) + private val initialSyncProgressService: Lazy, + private val homeServerCapabilitiesService: Lazy) : Session, RoomService by roomService.get(), RoomDirectoryService by roomDirectoryService.get(), @@ -81,7 +87,8 @@ internal class DefaultSession @Inject constructor(override val sessionParams: Se PushersService by pushersService.get(), FileService by fileService.get(), InitialSyncProgressService by initialSyncProgressService.get(), - SecureStorageService by secureStorageService.get() { + SecureStorageService by secureStorageService.get(), + HomeServerCapabilitiesService by homeServerCapabilitiesService.get() { private var isOpen = false @@ -93,6 +100,7 @@ internal class DefaultSession @Inject constructor(override val sessionParams: Se assert(!isOpen) isOpen = true liveEntityObservers.forEach { it.start() } + EventBus.getDefault().register(this) } override fun requireBackgroundSync() { @@ -132,6 +140,7 @@ internal class DefaultSession @Inject constructor(override val sessionParams: Se liveEntityObservers.forEach { it.dispose() } cryptoService.get().close() isOpen = false + EventBus.getDefault().unregister(this) } override fun syncState(): LiveData { @@ -160,6 +169,11 @@ internal class DefaultSession @Inject constructor(override val sessionParams: Se }) } + @Subscribe(threadMode = ThreadMode.MAIN) + fun onConsentNotGivenError(consentNotGivenError: ConsentNotGivenError) { + sessionListeners.dispatchConsentNotGiven(consentNotGivenError) + } + override fun contentUrlResolver() = contentUrlResolver override fun contentUploadProgressTracker() = contentUploadProgressTracker @@ -179,5 +193,4 @@ internal class DefaultSession @Inject constructor(override val sessionParams: Se throw IllegalStateException("This method can only be called on the main thread!") } } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionComponent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionComponent.kt index c8745fc356..8c16050442 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionComponent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionComponent.kt @@ -30,6 +30,7 @@ import im.vector.matrix.android.internal.session.content.UploadContentWorker import im.vector.matrix.android.internal.session.filter.FilterModule import im.vector.matrix.android.internal.session.group.GetGroupDataWorker import im.vector.matrix.android.internal.session.group.GroupModule +import im.vector.matrix.android.internal.session.homeserver.HomeServerCapabilitiesModule import im.vector.matrix.android.internal.session.pushers.AddHttpPusherWorker import im.vector.matrix.android.internal.session.pushers.PushersModule import im.vector.matrix.android.internal.session.room.RoomModule @@ -51,6 +52,7 @@ import im.vector.matrix.android.internal.task.TaskExecutor SessionModule::class, RoomModule::class, SyncModule::class, + HomeServerCapabilitiesModule::class, SignOutModule::class, GroupModule::class, UserModule::class, @@ -99,8 +101,4 @@ internal interface SessionComponent { matrixComponent: MatrixComponent, @BindsInstance sessionParams: SessionParams): SessionComponent } - - } - - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionListeners.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionListeners.kt index 51b7354785..25678bef66 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionListeners.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionListeners.kt @@ -16,19 +16,31 @@ package im.vector.matrix.android.internal.session +import im.vector.matrix.android.api.failure.ConsentNotGivenError import im.vector.matrix.android.api.session.Session import javax.inject.Inject -internal class SessionListeners @Inject constructor(){ +internal class SessionListeners @Inject constructor() { private val listeners = ArrayList() fun addListener(listener: Session.Listener) { - listeners.add(listener) + synchronized(listeners) { + listeners.add(listener) + } } fun removeListener(listener: Session.Listener) { - listeners.remove(listener) + synchronized(listeners) { + listeners.remove(listener) + } } -} \ No newline at end of file + fun dispatchConsentNotGiven(consentNotGivenError: ConsentNotGivenError) { + synchronized(listeners) { + listeners.forEach { + it.onConsentNotGivenError(consentNotGivenError) + } + } + } +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionModule.kt index a08c7e4ab7..d038630a74 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionModule.kt @@ -27,15 +27,16 @@ import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig import im.vector.matrix.android.api.auth.data.SessionParams import im.vector.matrix.android.api.session.InitialSyncProgressService import im.vector.matrix.android.api.session.Session +import im.vector.matrix.android.api.session.homeserver.HomeServerCapabilitiesService import im.vector.matrix.android.api.session.securestorage.SecureStorageService import im.vector.matrix.android.internal.database.LiveEntityObserver -import im.vector.matrix.android.internal.database.RealmKeysUtils -import im.vector.matrix.android.internal.database.model.SessionRealmModule +import im.vector.matrix.android.internal.database.SessionRealmConfigurationFactory import im.vector.matrix.android.internal.di.* import im.vector.matrix.android.internal.network.AccessTokenInterceptor import im.vector.matrix.android.internal.network.RetrofitFactory import im.vector.matrix.android.internal.network.interceptors.CurlLoggingInterceptor import im.vector.matrix.android.internal.session.group.GroupSummaryUpdater +import im.vector.matrix.android.internal.session.homeserver.DefaultHomeServerCapabilitiesService import im.vector.matrix.android.internal.session.room.EventRelationsAggregationUpdater import im.vector.matrix.android.internal.session.room.create.RoomCreateEventLiveObserver import im.vector.matrix.android.internal.session.room.prune.EventsPruner @@ -52,6 +53,7 @@ internal abstract class SessionModule { @Module companion object { + internal const val DB_ALIAS_PREFIX = "session_db_" @JvmStatic @@ -60,7 +62,6 @@ internal abstract class SessionModule { return sessionParams.homeServerConnectionConfig } - @JvmStatic @Provides fun providesCredentials(sessionParams: SessionParams): Credentials { @@ -92,18 +93,8 @@ internal abstract class SessionModule { @Provides @SessionDatabase @SessionScope - fun providesRealmConfiguration(realmKeysUtils: RealmKeysUtils, - @UserCacheDirectory directory: File, - @UserMd5 userMd5: String): RealmConfiguration { - return RealmConfiguration.Builder() - .directory(directory) - .name("disk_store.realm") - .apply { - realmKeysUtils.configureEncryption(this, "$DB_ALIAS_PREFIX$userMd5") - } - .modules(SessionRealmModule()) - .deleteRealmIfMigrationNeeded() - .build() + fun providesRealmConfiguration(realmConfigurationFactory: SessionRealmConfigurationFactory): RealmConfiguration { + return realmConfigurationFactory.create() } @JvmStatic @@ -162,7 +153,7 @@ internal abstract class SessionModule { @Binds @IntoSet - abstract fun bindEventRelationsAggregationUpdater(groupSummaryUpdater: EventRelationsAggregationUpdater): LiveEntityObserver + abstract fun bindEventRelationsAggregationUpdater(eventRelationsAggregationUpdater: EventRelationsAggregationUpdater): LiveEntityObserver @Binds @IntoSet @@ -178,4 +169,6 @@ internal abstract class SessionModule { @Binds abstract fun bindSecureStorageService(secureStorageService: DefaultSecureStorageService): SecureStorageService + @Binds + abstract fun bindHomeServerCapabilitiesService(homeServerCapabilitiesService: DefaultHomeServerCapabilitiesService): HomeServerCapabilitiesService } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionScope.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionScope.kt index 37753fdfcc..ab0c3f5770 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionScope.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionScope.kt @@ -21,4 +21,4 @@ import javax.inject.Scope @Scope @MustBeDocumented @Retention(AnnotationRetention.RUNTIME) -annotation class SessionScope \ No newline at end of file +internal annotation class SessionScope diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/cache/CacheModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/cache/CacheModule.kt index 96f6fbd8e0..a418109cec 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/cache/CacheModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/cache/CacheModule.kt @@ -38,5 +38,4 @@ internal abstract class CacheModule { @Binds abstract fun bindCacheService(cacheService: DefaultCacheService): CacheService - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/cache/ClearCacheTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/cache/ClearCacheTask.kt index 5af4ee74fb..cd802d40dc 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/cache/ClearCacheTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/cache/ClearCacheTask.kt @@ -30,4 +30,4 @@ internal class RealmClearCacheTask @Inject constructor(private val realmConfigur it.deleteAll() } } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/cache/DefaultCacheService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/cache/DefaultCacheService.kt index 12684965b7..63db2b4b86 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/cache/DefaultCacheService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/cache/DefaultCacheService.kt @@ -35,4 +35,4 @@ internal class DefaultCacheService @Inject constructor(@SessionDatabase } .executeBy(taskExecutor) } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/content/ContentUploadResponse.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/content/ContentUploadResponse.kt index e1f456fe5f..242502a5bc 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/content/ContentUploadResponse.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/content/ContentUploadResponse.kt @@ -22,4 +22,4 @@ import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) data class ContentUploadResponse( @Json(name = "content_uri") val contentUri: String -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/content/DefaultContentUploadStateTracker.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/content/DefaultContentUploadStateTracker.kt index e44c8eb5ee..68f48d20db 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/content/DefaultContentUploadStateTracker.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/content/DefaultContentUploadStateTracker.kt @@ -75,10 +75,7 @@ internal class DefaultContentUploadStateTracker @Inject constructor() : ContentU private fun updateState(key: String, state: ContentUploadStateTracker.State) { states[key] = state mainHandler.post { - listeners[key]?.also { listeners -> - listeners.forEach { it.onUpdate(state) } - } + listeners[key]?.forEach { it.onUpdate(state) } } } - } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/content/DefaultContentUrlResolver.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/content/DefaultContentUrlResolver.kt index 55508b11b3..f288f949cd 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/content/DefaultContentUrlResolver.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/content/DefaultContentUrlResolver.kt @@ -20,7 +20,6 @@ import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig import im.vector.matrix.android.api.session.content.ContentUrlResolver import javax.inject.Inject - private const val MATRIX_CONTENT_URI_SCHEME = "mxc://" private const val URI_PREFIX_CONTENT_API = "_matrix/media/v1/" @@ -59,7 +58,6 @@ internal class DefaultContentUrlResolver @Inject constructor(private val homeSer contentUrl: String, prefix: String, params: String? = null): String? { - var serverAndMediaId = contentUrl.removePrefix(MATRIX_CONTENT_URI_SCHEME) val fragmentOffset = serverAndMediaId.indexOf("#") var fragment = "" @@ -76,5 +74,4 @@ internal class DefaultContentUrlResolver @Inject constructor(private val homeSer private fun String.isValidMatrixContentUrl(): Boolean { return startsWith(MATRIX_CONTENT_URI_SCHEME) } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/content/FileUploader.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/content/FileUploader.kt index 2ec17248d1..209f03ad9d 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/content/FileUploader.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/content/FileUploader.kt @@ -16,49 +16,49 @@ package im.vector.matrix.android.internal.session.content -import arrow.core.Try -import arrow.core.Try.Companion.raise import com.squareup.moshi.Moshi import im.vector.matrix.android.api.auth.data.SessionParams import im.vector.matrix.android.internal.di.Authenticated import im.vector.matrix.android.internal.network.ProgressRequestBody -import okhttp3.* +import im.vector.matrix.android.internal.network.awaitResponse +import im.vector.matrix.android.internal.network.toFailure +import okhttp3.HttpUrl.Companion.toHttpUrlOrNull +import okhttp3.MediaType.Companion.toMediaTypeOrNull +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.RequestBody +import okhttp3.RequestBody.Companion.asRequestBody +import okhttp3.RequestBody.Companion.toRequestBody import java.io.File import java.io.IOException import javax.inject.Inject - internal class FileUploader @Inject constructor(@Authenticated private val okHttpClient: OkHttpClient, - private val sessionParams: SessionParams, - private val moshi: Moshi) { + sessionParams: SessionParams, + moshi: Moshi) { private val uploadUrl = DefaultContentUrlResolver.getUploadUrl(sessionParams.homeServerConnectionConfig) private val responseAdapter = moshi.adapter(ContentUploadResponse::class.java) - - fun uploadFile(file: File, - filename: String?, - mimeType: String, - progressListener: ProgressRequestBody.Listener? = null): Try { - - val uploadBody = RequestBody.create(MediaType.parse(mimeType), file) - return upload(uploadBody, filename, progressListener) - - } - - fun uploadByteArray(byteArray: ByteArray, - filename: String?, - mimeType: String, - progressListener: ProgressRequestBody.Listener? = null): Try { - - val uploadBody = RequestBody.create(MediaType.parse(mimeType), byteArray) + suspend fun uploadFile(file: File, + filename: String?, + mimeType: String, + progressListener: ProgressRequestBody.Listener? = null): ContentUploadResponse { + val uploadBody = file.asRequestBody(mimeType.toMediaTypeOrNull()) return upload(uploadBody, filename, progressListener) } + 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) + } - private fun upload(uploadBody: RequestBody, filename: String?, progressListener: ProgressRequestBody.Listener?): Try { - val urlBuilder = HttpUrl.parse(uploadUrl)?.newBuilder() ?: return raise(RuntimeException()) + private suspend fun upload(uploadBody: RequestBody, filename: String?, progressListener: ProgressRequestBody.Listener?): ContentUploadResponse { + val urlBuilder = uploadUrl.toHttpUrlOrNull()?.newBuilder() ?: throw RuntimeException() val httpUrl = urlBuilder .addQueryParameter("filename", filename) @@ -71,19 +71,15 @@ internal class FileUploader @Inject constructor(@Authenticated .post(requestBody) .build() - return Try { - okHttpClient.newCall(request).execute().use { response -> - if (!response.isSuccessful) { - throw IOException() - } else { - response.body()?.source()?.let { - responseAdapter.fromJson(it) - } - ?: throw IOException() + return okHttpClient.newCall(request).awaitResponse().use { response -> + if (!response.isSuccessful) { + throw response.toFailure() + } else { + response.body?.source()?.let { + responseAdapter.fromJson(it) } + ?: throw IOException() } } - } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/content/ThumbnailExtractor.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/content/ThumbnailExtractor.kt index 8fc6f5f983..f8935e9283 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/content/ThumbnailExtractor.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/content/ThumbnailExtractor.kt @@ -63,6 +63,4 @@ internal object ThumbnailExtractor { outputStream.reset() return thumbnailData } - - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/content/UploadContentWorker.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/content/UploadContentWorker.kt index b015670daa..a05edb7b0f 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/content/UploadContentWorker.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/content/UploadContentWorker.kt @@ -38,7 +38,6 @@ import java.io.File import java.io.FileInputStream import javax.inject.Inject - internal class UploadContentWorker(context: Context, params: WorkerParameters) : CoroutineWorker(context, params) { @JsonClass(generateAdapter = true) @@ -93,32 +92,28 @@ internal class UploadContentWorker(context: Context, params: WorkerParameters) : } } - val contentUploadResponse = if (params.isRoomEncrypted) { - Timber.v("Encrypt thumbnail") - contentUploadStateTracker.setEncryptingThumbnail(eventId) - MXEncryptedAttachments.encryptAttachment(ByteArrayInputStream(thumbnailData.bytes), thumbnailData.mimeType) - .flatMap { encryptionResult -> - uploadedThumbnailEncryptedFileInfo = encryptionResult.encryptedFileInfo + try { + val contentUploadResponse = if (params.isRoomEncrypted) { + Timber.v("Encrypt thumbnail") + contentUploadStateTracker.setEncryptingThumbnail(eventId) + val encryptionResult = MXEncryptedAttachments.encryptAttachment(ByteArrayInputStream(thumbnailData.bytes), thumbnailData.mimeType) + uploadedThumbnailEncryptedFileInfo = encryptionResult.encryptedFileInfo + fileUploader.uploadByteArray(encryptionResult.encryptedByteArray, + "thumb_${attachment.name}", + "application/octet-stream", + thumbnailProgressListener) + } else { + fileUploader.uploadByteArray(thumbnailData.bytes, + "thumb_${attachment.name}", + thumbnailData.mimeType, + thumbnailProgressListener) + } - fileUploader - .uploadByteArray(encryptionResult.encryptedByteArray, - "thumb_${attachment.name}", - "application/octet-stream", - thumbnailProgressListener) - } - } else { - fileUploader - .uploadByteArray(thumbnailData.bytes, - "thumb_${attachment.name}", - thumbnailData.mimeType, - thumbnailProgressListener) + uploadedThumbnailUrl = contentUploadResponse.contentUri + } catch (t: Throwable) { + Timber.e(t) + return handleFailure(params, t) } - - contentUploadResponse - .fold( - { Timber.e(it) }, - { uploadedThumbnailUrl = it.contentUri } - ) } val progressListener = object : ProgressRequestBody.Listener { @@ -133,27 +128,26 @@ internal class UploadContentWorker(context: Context, params: WorkerParameters) : var uploadedFileEncryptedFileInfo: EncryptedFileInfo? = null - val contentUploadResponse = if (params.isRoomEncrypted) { - Timber.v("Encrypt file") - contentUploadStateTracker.setEncrypting(eventId) + return try { + val contentUploadResponse = if (params.isRoomEncrypted) { + Timber.v("Encrypt file") + contentUploadStateTracker.setEncrypting(eventId) - MXEncryptedAttachments.encryptAttachment(FileInputStream(attachmentFile), attachment.mimeType) - .flatMap { encryptionResult -> - uploadedFileEncryptedFileInfo = encryptionResult.encryptedFileInfo + val encryptionResult = MXEncryptedAttachments.encryptAttachment(FileInputStream(attachmentFile), attachment.mimeType) + uploadedFileEncryptedFileInfo = encryptionResult.encryptedFileInfo - fileUploader - .uploadByteArray(encryptionResult.encryptedByteArray, attachment.name, "application/octet-stream", progressListener) - } - } else { - fileUploader - .uploadFile(attachmentFile, attachment.name, attachment.mimeType, progressListener) + fileUploader + .uploadByteArray(encryptionResult.encryptedByteArray, attachment.name, "application/octet-stream", progressListener) + } else { + fileUploader + .uploadFile(attachmentFile, attachment.name, attachment.mimeType, progressListener) + } + + handleSuccess(params, contentUploadResponse.contentUri, uploadedFileEncryptedFileInfo, uploadedThumbnailUrl, uploadedThumbnailEncryptedFileInfo) + } catch (t: Throwable) { + Timber.e(t) + handleFailure(params, t) } - - return contentUploadResponse - .fold( - { handleFailure(params, it) }, - { handleSuccess(params, it.contentUri, uploadedFileEncryptedFileInfo, uploadedThumbnailUrl, uploadedThumbnailEncryptedFileInfo) } - ) } private fun handleFailure(params: Params, failure: Throwable): Result { @@ -217,7 +211,6 @@ internal class UploadContentWorker(context: Context, params: WorkerParameters) : ) } - private fun MessageFileContent.update(url: String, encryptedFileInfo: EncryptedFileInfo?): MessageFileContent { return copy( @@ -233,6 +226,4 @@ internal class UploadContentWorker(context: Context, params: WorkerParameters) : encryptedFileInfo = encryptedFileInfo?.copy(url = url) ) } - } - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/DefaultFilterRepository.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/DefaultFilterRepository.kt index c46da8b318..02e6db189a 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/DefaultFilterRepository.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/DefaultFilterRepository.kt @@ -108,4 +108,4 @@ internal class DefaultFilterRepository @Inject constructor( return result } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/DefaultFilterService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/DefaultFilterService.kt index 445e416b45..84e820ebca 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/DefaultFilterService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/DefaultFilterService.kt @@ -53,4 +53,4 @@ internal class DefaultFilterService @Inject constructor(private val filterReposi .executeBy(taskExecutor) } } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/DefaultSaveFilterTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/DefaultSaveFilterTask.kt index 8df7426263..b98049675e 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/DefaultSaveFilterTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/DefaultSaveFilterTask.kt @@ -21,7 +21,6 @@ import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.task.Task import javax.inject.Inject - /** * Save a filter to the server */ @@ -30,7 +29,6 @@ internal interface SaveFilterTask : Task { data class Params( val filter: FilterBody ) - } internal class DefaultSaveFilterTask @Inject constructor(@UserId private val userId: String, @@ -45,5 +43,4 @@ internal class DefaultSaveFilterTask @Inject constructor(@UserId private val use } filterRepository.storeFilterId(params.filter, filterResponse.filterId) } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/FilterBody.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/FilterBody.kt index 8abf6f3fb8..fa66470c9b 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/FilterBody.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/FilterBody.kt @@ -19,7 +19,6 @@ import com.squareup.moshi.Json import com.squareup.moshi.JsonClass import im.vector.matrix.android.internal.di.MoshiProvider - /** * Class which can be parsed to a filter json string. Used for POST and GET * Have a look here for further information: diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/FilterFactory.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/FilterFactory.kt index d5c93ac350..86c94d3dfa 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/FilterFactory.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/FilterFactory.kt @@ -73,4 +73,4 @@ internal object FilterFactory { // TODO Complete the list EventType.STATE_ROOM_MEMBER ) -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/FilterModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/FilterModule.kt index 745a92b3f9..7b787048c5 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/FilterModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/FilterModule.kt @@ -43,7 +43,5 @@ internal abstract class FilterModule { abstract fun bindFilterService(filterService: DefaultFilterService): FilterService @Binds - abstract fun bindSaveFilterTask(saveFilterTask_Factory: DefaultSaveFilterTask): SaveFilterTask - - -} \ No newline at end of file + abstract fun bindSaveFilterTask(saveFilterTask: DefaultSaveFilterTask): SaveFilterTask +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/FilterRepository.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/FilterRepository.kt index f48153e9be..092d9ff766 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/FilterRepository.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/FilterRepository.kt @@ -37,4 +37,4 @@ internal interface FilterRepository { * Return the room filter */ fun getRoomFilter(): String -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/FilterUtil.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/FilterUtil.kt index 526191cf2f..d3020b3fa6 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/FilterUtil.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/FilterUtil.kt @@ -55,7 +55,6 @@ internal object FilterUtil { } } } else { - filterBody.room?.let { room -> room.ephemeral?.types?.remove("m.receipt") if (room.ephemeral?.types?.isEmpty() == true) { diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/RoomEventFilter.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/RoomEventFilter.kt index 1d8720a9af..ee81e399ee 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/RoomEventFilter.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/RoomEventFilter.kt @@ -51,6 +51,4 @@ data class RoomEventFilter( || containsUrl != null || lazyLoadMembers != null) } - } - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/RoomFilter.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/RoomFilter.kt index 4c8fc1662c..4742bdb988 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/RoomFilter.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/RoomFilter.kt @@ -42,5 +42,4 @@ data class RoomFilter( || timeline != null || accountData != null) } - } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/DefaultGetGroupDataTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/DefaultGetGroupDataTask.kt index 003f6a8c61..40dc0a44c0 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/DefaultGetGroupDataTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/DefaultGetGroupDataTask.kt @@ -30,7 +30,6 @@ import javax.inject.Inject internal interface GetGroupDataTask : Task { data class Params(val groupId: String) - } internal class DefaultGetGroupDataTask @Inject constructor( @@ -52,7 +51,6 @@ internal class DefaultGetGroupDataTask @Inject constructor( insertInDb(groupSummary, groupRooms, groupUsers, groupId) } - private fun insertInDb(groupSummary: GroupSummaryResponse, groupRooms: GroupRooms, groupUsers: GroupUsers, @@ -67,13 +65,11 @@ internal class DefaultGetGroupDataTask @Inject constructor( groupSummaryEntity.displayName = if (name.isNullOrEmpty()) groupId else name groupSummaryEntity.shortDescription = groupSummary.profile?.shortDescription ?: "" - val roomIds = groupRooms.rooms.map { it.roomId } groupSummaryEntity.roomIds.clear() - groupSummaryEntity.roomIds.addAll(roomIds) + groupRooms.rooms.mapTo(groupSummaryEntity.roomIds) { it.roomId } - val userIds = groupUsers.users.map { it.userId } groupSummaryEntity.userIds.clear() - groupSummaryEntity.userIds.addAll(userIds) + groupUsers.users.mapTo(groupSummaryEntity.userIds) { it.userId } groupSummaryEntity.membership = when (groupSummary.user?.membership) { Membership.JOIN.value -> Membership.JOIN @@ -82,4 +78,4 @@ internal class DefaultGetGroupDataTask @Inject constructor( } } } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/DefaultGroup.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/DefaultGroup.kt index f7e2a23c2d..6c7b5b2a8b 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/DefaultGroup.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/DefaultGroup.kt @@ -18,6 +18,4 @@ package im.vector.matrix.android.internal.session.group import im.vector.matrix.android.api.session.group.Group -internal class DefaultGroup(override val groupId: String) : Group { - -} \ No newline at end of file +internal class DefaultGroup(override val groupId: String) : Group diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/DefaultGroupService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/DefaultGroupService.kt index a574df7c8f..be059038f3 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/DefaultGroupService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/DefaultGroupService.kt @@ -39,5 +39,4 @@ internal class DefaultGroupService @Inject constructor(private val monarchy: Mon { it.asDomain() } ) } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/GetGroupDataWorker.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/GetGroupDataWorker.kt index 913a468bd7..76a7d5a48d 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/GetGroupDataWorker.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/GetGroupDataWorker.kt @@ -52,5 +52,4 @@ internal class GetGroupDataWorker(context: Context, params: WorkerParameters) : private suspend fun fetchGroupData(groupId: String) { getGroupDataTask.execute(GetGroupDataTask.Params(groupId)) } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/GroupAPI.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/GroupAPI.kt index a0f902bf2e..8d5dd03fb2 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/GroupAPI.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/GroupAPI.kt @@ -42,7 +42,6 @@ internal interface GroupAPI { @GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "groups/{groupId}/rooms") fun getRooms(@Path("groupId") groupId: String): Call - /** * Request the users list. * @@ -50,6 +49,4 @@ internal interface GroupAPI { */ @GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "groups/{groupId}/users") fun getUsers(@Path("groupId") groupId: String): Call - - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/GroupModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/GroupModule.kt index cdb698b003..3b88dc5b6b 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/GroupModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/GroupModule.kt @@ -41,4 +41,4 @@ internal abstract class GroupModule { @Binds abstract fun bindGroupService(groupService: DefaultGroupService): GroupService -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/GroupSummaryUpdater.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/GroupSummaryUpdater.kt index 12a256e7dc..9eceb44417 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/GroupSummaryUpdater.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/GroupSummaryUpdater.kt @@ -85,4 +85,4 @@ internal class GroupSummaryUpdater @Inject constructor(private val context: Cont .deleteAllFromRealm() } } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/model/GroupSummaryRoomsSection.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/model/GroupSummaryRoomsSection.kt index 2b1a8f226e..75d35f07ce 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/model/GroupSummaryRoomsSection.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/model/GroupSummaryRoomsSection.kt @@ -30,5 +30,5 @@ internal data class GroupSummaryRoomsSection( @Json(name = "rooms") val rooms: List = emptyList() // @TODO: Check the meaning and the usage of these categories. This dictionary is empty FTM. - //public Map categories; + // public Map categories; ) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/model/GroupSummaryUsersSection.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/model/GroupSummaryUsersSection.kt index 53bb1ab9c3..52bced1c39 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/model/GroupSummaryUsersSection.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/model/GroupSummaryUsersSection.kt @@ -19,7 +19,6 @@ package im.vector.matrix.android.internal.session.group.model import com.squareup.moshi.Json import com.squareup.moshi.JsonClass - /** * This class represents the community members in a group summary response. */ @@ -32,5 +31,5 @@ internal data class GroupSummaryUsersSection( @Json(name = "users") val users: List = emptyList() // @TODO: Check the meaning and the usage of these roles. This dictionary is empty FTM. - //public Map roles; + // public Map roles; ) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/model/GroupUser.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/model/GroupUser.kt index 62be8f5e7e..f2e504dd47 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/model/GroupUser.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/model/GroupUser.kt @@ -26,4 +26,4 @@ internal data class GroupUser( @Json(name = "is_privileged") val isPrivileged: Boolean = false, @Json(name = "avatar_url") val avatarUrl: String? = "", @Json(name = "is_public") val isPublic: Boolean = false -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/model/GroupUsers.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/model/GroupUsers.kt index b04ebc7ca7..b98d467c55 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/model/GroupUsers.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/model/GroupUsers.kt @@ -23,4 +23,4 @@ import com.squareup.moshi.JsonClass internal data class GroupUsers( @Json(name = "total_user_count_estimate") val totalUserCountEstimate: Int, @Json(name = "chunk") val users: List = emptyList() -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/homeserver/CapabilitiesAPI.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/homeserver/CapabilitiesAPI.kt new file mode 100644 index 0000000000..f2015229fd --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/homeserver/CapabilitiesAPI.kt @@ -0,0 +1,30 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.matrix.android.internal.session.homeserver + +import im.vector.matrix.android.internal.network.NetworkConstants +import retrofit2.Call +import retrofit2.http.GET + +internal interface CapabilitiesAPI { + + /** + * Request the upload capabilities + */ + @GET(NetworkConstants.URI_API_MEDIA_PREFIX_PATH_R0 + "config") + fun getUploadCapabilities(): Call +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/homeserver/DefaultGetHomeServerCapabilitiesTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/homeserver/DefaultGetHomeServerCapabilitiesTask.kt new file mode 100644 index 0000000000..98ab0b5389 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/homeserver/DefaultGetHomeServerCapabilitiesTask.kt @@ -0,0 +1,72 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.matrix.android.internal.session.homeserver + +import com.zhuinden.monarchy.Monarchy +import im.vector.matrix.android.api.session.homeserver.HomeServerCapabilities +import im.vector.matrix.android.internal.database.model.HomeServerCapabilitiesEntity +import im.vector.matrix.android.internal.database.query.getOrCreate +import im.vector.matrix.android.internal.network.executeRequest +import im.vector.matrix.android.internal.task.Task +import im.vector.matrix.android.internal.util.awaitTransaction +import java.util.* +import javax.inject.Inject + +internal interface GetHomeServerCapabilitiesTask : Task + +internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor( + private val capabilitiesAPI: CapabilitiesAPI, + private val monarchy: Monarchy +) : GetHomeServerCapabilitiesTask { + + override suspend fun execute(params: Unit) { + var doRequest = false + monarchy.awaitTransaction { realm -> + val homeServerCapabilitiesEntity = HomeServerCapabilitiesEntity.getOrCreate(realm) + + doRequest = homeServerCapabilitiesEntity.lastUpdatedTimestamp + MIN_DELAY_BETWEEN_TWO_REQUEST_MILLIS < Date().time + } + + if (!doRequest) { + return + } + + val uploadCapabilities = executeRequest { + apiCall = capabilitiesAPI.getUploadCapabilities() + } + + // TODO Add other call here (get version, etc.) + + insertInDb(uploadCapabilities) + } + + private suspend fun insertInDb(getUploadCapabilitiesResult: GetUploadCapabilitiesResult) { + monarchy.awaitTransaction { realm -> + val homeServerCapabilitiesEntity = HomeServerCapabilitiesEntity.getOrCreate(realm) + + homeServerCapabilitiesEntity.maxUploadFileSize = getUploadCapabilitiesResult.maxUploadSize + ?: HomeServerCapabilities.MAX_UPLOAD_FILE_SIZE_UNKNOWN + + homeServerCapabilitiesEntity.lastUpdatedTimestamp = Date().time + } + } + + companion object { + // 8 hours like on Riot Web + private const val MIN_DELAY_BETWEEN_TWO_REQUEST_MILLIS = 8 * 60 * 60 * 1000 + } +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/homeserver/DefaultHomeServerCapabilitiesService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/homeserver/DefaultHomeServerCapabilitiesService.kt new file mode 100644 index 0000000000..ea41eb12b5 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/homeserver/DefaultHomeServerCapabilitiesService.kt @@ -0,0 +1,38 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.matrix.android.internal.session.homeserver + +import com.zhuinden.monarchy.Monarchy +import im.vector.matrix.android.api.session.homeserver.HomeServerCapabilities +import im.vector.matrix.android.api.session.homeserver.HomeServerCapabilitiesService +import im.vector.matrix.android.internal.database.mapper.HomeServerCapabilitiesMapper +import im.vector.matrix.android.internal.database.model.HomeServerCapabilitiesEntity +import im.vector.matrix.android.internal.database.query.get +import io.realm.Realm +import javax.inject.Inject + +internal class DefaultHomeServerCapabilitiesService @Inject constructor(private val monarchy: Monarchy) : HomeServerCapabilitiesService { + + override fun getHomeServerCapabilities(): HomeServerCapabilities { + return Realm.getInstance(monarchy.realmConfiguration).use { realm -> + HomeServerCapabilitiesEntity.get(realm)?.let { + HomeServerCapabilitiesMapper.map(it) + } + } + ?: HomeServerCapabilities() + } +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/homeserver/GetUploadCapabilitiesResult.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/homeserver/GetUploadCapabilitiesResult.kt new file mode 100644 index 0000000000..8e410cc834 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/homeserver/GetUploadCapabilitiesResult.kt @@ -0,0 +1,30 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.matrix.android.internal.session.homeserver + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +data class GetUploadCapabilitiesResult( + /** + * The maximum size an upload can be in bytes. Clients SHOULD use this as a guide when uploading content. + * If not listed or null, the size limit should be treated as unknown. + */ + @Json(name = "m.upload.size") + val maxUploadSize: Long? = null +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/homeserver/HomeServerCapabilitiesModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/homeserver/HomeServerCapabilitiesModule.kt new file mode 100644 index 0000000000..9082fceb9e --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/homeserver/HomeServerCapabilitiesModule.kt @@ -0,0 +1,40 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.matrix.android.internal.session.homeserver + +import dagger.Binds +import dagger.Module +import dagger.Provides +import im.vector.matrix.android.internal.session.SessionScope +import retrofit2.Retrofit + +@Module +internal abstract class HomeServerCapabilitiesModule { + + @Module + companion object { + @Provides + @JvmStatic + @SessionScope + fun providesCapabilitiesAPI(retrofit: Retrofit): CapabilitiesAPI { + return retrofit.create(CapabilitiesAPI::class.java) + } + } + + @Binds + abstract fun bindGetHomeServerCapabilitiesTask(getHomeServerCapabilitiesTask: DefaultGetHomeServerCapabilitiesTask): GetHomeServerCapabilitiesTask +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/notification/DefaultPushRuleService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/notification/DefaultPushRuleService.kt index fb436c3b21..82b928fc54 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/notification/DefaultPushRuleService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/notification/DefaultPushRuleService.kt @@ -42,7 +42,7 @@ internal class DefaultPushRuleService @Inject constructor(private val getPushRul private val monarchy: Monarchy ) : PushRuleService { - private var listeners = ArrayList() + private var listeners = mutableSetOf() override fun fetchPushRules(scope: String) { getPushRulesTask @@ -90,22 +90,24 @@ internal class DefaultPushRuleService @Inject constructor(private val getPushRul } override fun updatePushRuleEnableStatus(kind: RuleKind, pushRule: PushRule, enabled: Boolean, callback: MatrixCallback): Cancelable { + // The rules will be updated, and will come back from the next sync response return updatePushRuleEnableStatusTask .configureWith(UpdatePushRuleEnableStatusTask.Params(kind, pushRule, enabled)) { this.callback = callback } - // TODO Fetch the rules .executeBy(taskExecutor) } override fun removePushRuleListener(listener: PushRuleService.PushRuleListener) { - listeners.remove(listener) + synchronized(listeners) { + listeners.remove(listener) + } } - override fun addPushRuleListener(listener: PushRuleService.PushRuleListener) { - if (!listeners.contains(listener)) + synchronized(listeners) { listeners.add(listener) + } } // fun processEvents(events: List) { @@ -121,43 +123,63 @@ internal class DefaultPushRuleService @Inject constructor(private val getPushRul // } fun dispatchBing(event: Event, rule: PushRule) { - try { + synchronized(listeners) { val actionsList = rule.getActions() listeners.forEach { - it.onMatchRule(event, actionsList) + try { + it.onMatchRule(event, actionsList) + } catch (e: Throwable) { + Timber.e(e, "Error while dispatching bing") + } } - } catch (e: Throwable) { - Timber.e(e, "Error while dispatching bing") } } - fun dispatchRoomLeft(roomid: String) { - try { + fun dispatchRoomJoined(roomId: String) { + synchronized(listeners) { listeners.forEach { - it.onRoomLeft(roomid) + try { + it.onRoomJoined(roomId) + } catch (e: Throwable) { + Timber.e(e, "Error while dispatching room joined") + } + } + } + } + + fun dispatchRoomLeft(roomId: String) { + synchronized(listeners) { + listeners.forEach { + try { + it.onRoomLeft(roomId) + } catch (e: Throwable) { + Timber.e(e, "Error while dispatching room left") + } } - } catch (e: Throwable) { - Timber.e(e, "Error while dispatching room left") } } fun dispatchRedactedEventId(redactedEventId: String) { - try { + synchronized(listeners) { listeners.forEach { - it.onEventRedacted(redactedEventId) + try { + it.onEventRedacted(redactedEventId) + } catch (e: Throwable) { + Timber.e(e, "Error while dispatching redacted event") + } } - } catch (e: Throwable) { - Timber.e(e, "Error while dispatching room left") } } fun dispatchFinish() { - try { + synchronized(listeners) { listeners.forEach { - it.batchFinish() + try { + it.batchFinish() + } catch (e: Throwable) { + Timber.e(e, "Error while dispatching finish") + } } - } catch (e: Throwable) { - Timber.e(e, "Error while dispatching finish") } } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/notification/ProcessEventForPushTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/notification/ProcessEventForPushTask.kt index e2db0362bb..6e47bdfeaa 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/notification/ProcessEventForPushTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/notification/ProcessEventForPushTask.kt @@ -45,20 +45,20 @@ internal class DefaultProcessEventForPushTask @Inject constructor( params.syncResponse.leave.keys.forEach { defaultPushRuleService.dispatchRoomLeft(it) } + // Handle joined rooms + params.syncResponse.join.keys.forEach { + defaultPushRuleService.dispatchRoomJoined(it) + } val newJoinEvents = params.syncResponse.join - .map { entries -> - entries.value.timeline?.events?.map { it.copy(roomId = entries.key) } + .mapNotNull { (key, value) -> + value.timeline?.events?.map { it.copy(roomId = key) } } - .fold(emptyList(), { acc, next -> - acc + (next ?: emptyList()) - }) + .flatten() val inviteEvents = params.syncResponse.invite - .map { entries -> - entries.value.inviteState?.events?.map { it.copy(roomId = entries.key) } + .mapNotNull { (key, value) -> + value.inviteState?.events?.map { it.copy(roomId = key) } } - .fold(emptyList(), { acc, next -> - acc + (next ?: emptyList()) - }) + .flatten() val allEvents = (newJoinEvents + inviteEvents).filter { event -> when (event.type) { EventType.MESSAGE, @@ -80,16 +80,12 @@ internal class DefaultProcessEventForPushTask @Inject constructor( } val allRedactedEvents = params.syncResponse.join - .map { entries -> - entries.value.timeline?.events?.filter { - it.type == EventType.REDACTION - } - .orEmpty() - .mapNotNull { it.redacts } - } - .fold(emptyList(), { acc, next -> - acc + next - }) + .asSequence() + .mapNotNull { (_, value) -> value.timeline?.events } + .flatten() + .filter { it.type == EventType.REDACTION } + .mapNotNull { it.redacts } + .toList() Timber.v("[PushRules] Found ${allRedactedEvents.size} redacted events") @@ -103,19 +99,11 @@ internal class DefaultProcessEventForPushTask @Inject constructor( private fun fulfilledBingRule(event: Event, rules: List): PushRule? { // TODO This should be injected val conditionResolver = DefaultConditionResolver(event, roomService, userId) - rules.filter { it.enabled }.forEach { rule -> - val isFullfilled = rule.conditions?.map { + return rules.firstOrNull { rule -> + // All conditions must hold true for an event in order to apply the action for the event. + rule.enabled && rule.conditions?.all { it.asExecutableCondition()?.isSatisfied(conditionResolver) ?: false - }?.fold(true/*A rule with no conditions always matches*/, { acc, next -> - //All conditions must hold true for an event in order to apply the action for the event. - acc && next - }) ?: false - - if (isFullfilled) { - return rule - } + } ?: false } - return null } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/AddHttpPusherWorker.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/AddHttpPusherWorker.kt index e230c02e49..9eed515d14 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/AddHttpPusherWorker.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/AddHttpPusherWorker.kt @@ -44,7 +44,6 @@ internal class AddHttpPusherWorker(context: Context, params: WorkerParameters) @Inject lateinit var monarchy: Monarchy override suspend fun doWork(): Result { - val params = WorkerParamsFactory.fromData(inputData) ?: return Result.failure() @@ -65,11 +64,11 @@ internal class AddHttpPusherWorker(context: Context, params: WorkerParameters) else -> { monarchy.awaitTransaction { realm -> PusherEntity.where(realm, pusher.pushKey).findFirst()?.let { - //update it + // update it it.state = PusherState.FAILED_TO_REGISTER } } - //always return success, or the chain will be stuck for ever! + // always return success, or the chain will be stuck for ever! Result.failure() } } @@ -83,7 +82,7 @@ internal class AddHttpPusherWorker(context: Context, params: WorkerParameters) monarchy.awaitTransaction { realm -> val echo = PusherEntity.where(realm, pusher.pushKey).findFirst() if (echo != null) { - //update it + // update it echo.appDisplayName = pusher.appDisplayName echo.appId = pusher.appId echo.kind = pusher.kind @@ -100,4 +99,4 @@ internal class AddHttpPusherWorker(context: Context, params: WorkerParameters) } } } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/DefaultConditionResolver.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/DefaultConditionResolver.kt index a40c5e801b..881d122606 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/DefaultConditionResolver.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/DefaultConditionResolver.kt @@ -26,7 +26,6 @@ internal class DefaultConditionResolver(private val event: Event, private val roomService: RoomService, @UserId private val userId: String) : ConditionResolver { - override fun resolveEventMatchCondition(eventMatchCondition: EventMatchCondition): Boolean { return eventMatchCondition.isSatisfied(event) } @@ -38,9 +37,9 @@ internal class DefaultConditionResolver(private val event: Event, override fun resolveSenderNotificationPermissionCondition(senderNotificationPermissionCondition: SenderNotificationPermissionCondition): Boolean { // val roomId = event.roomId ?: return false // val room = roomService.getRoom(roomId) ?: return false - //TODO RoomState not yet managed + // TODO RoomState not yet managed Timber.e("POWER LEVELS STATE NOT YET MANAGED BY RIOTX") - return false //senderNotificationPermissionCondition.isSatisfied(event, ) + return false // senderNotificationPermissionCondition.isSatisfied(event, ) } override fun resolveContainsDisplayNameCondition(containsDisplayNameCondition: ContainsDisplayNameCondition): Boolean { @@ -49,4 +48,4 @@ internal class DefaultConditionResolver(private val event: Event, val myDisplayName = room.getRoomMember(userId)?.displayName ?: return false return containsDisplayNameCondition.isSatisfied(event, myDisplayName) } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/DefaultPusherService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/DefaultPusherService.kt index 12f6ee9f01..243e4d4b03 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/DefaultPusherService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/DefaultPusherService.kt @@ -36,7 +36,6 @@ import java.util.* import java.util.concurrent.TimeUnit import javax.inject.Inject - internal class DefaultPusherService @Inject constructor(private val context: Context, private val monarchy: Monarchy, @UserId private val userId: String, @@ -45,7 +44,6 @@ internal class DefaultPusherService @Inject constructor(private val context: Con private val taskExecutor: TaskExecutor ) : PushersService { - override fun refreshPushers() { getPusherTask .configureWith() @@ -56,7 +54,6 @@ internal class DefaultPusherService @Inject constructor(private val context: Con lang: String, appDisplayName: String, deviceDisplayName: String, url: String, append: Boolean, withEventIdOnly: Boolean) : UUID { - val pusher = JsonPusher( pushKey = pushkey, kind = "http", @@ -68,7 +65,6 @@ internal class DefaultPusherService @Inject constructor(private val context: Con data = JsonPusherData(url, if (withEventIdOnly) PushersService.EVENT_ID_ONLY else null), append = append) - val params = AddHttpPusherWorker.Params(pusher, userId) val request = matrixOneTimeWorkRequestBuilder() @@ -86,7 +82,7 @@ internal class DefaultPusherService @Inject constructor(private val context: Con .configureWith(params) { this.callback = callback } - //.enableRetry() ?? + // .enableRetry() ?? .executeBy(taskExecutor) } @@ -100,4 +96,4 @@ internal class DefaultPusherService @Inject constructor(private val context: Con override fun pushers(): List { return monarchy.fetchAllCopiedSync { PusherEntity.where(it) }.map { it.asDomain() } } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/GetPushRulesTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/GetPushRulesTask.kt index d542a8fffc..d135c36543 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/GetPushRulesTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/GetPushRulesTask.kt @@ -20,7 +20,6 @@ import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.task.Task import javax.inject.Inject - internal interface GetPushRulesTask : Task { data class Params(val scope: String) } @@ -38,4 +37,4 @@ internal class DefaultGetPushRulesTask @Inject constructor(private val pushRules savePushRulesTask.execute(SavePushRulesTask.Params(response)) } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/GetPushersResponse.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/GetPushersResponse.kt index 4f4cac9302..1a46dcc8be 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/GetPushersResponse.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/GetPushersResponse.kt @@ -18,9 +18,8 @@ package im.vector.matrix.android.internal.session.pushers import com.squareup.moshi.Json import com.squareup.moshi.JsonClass - @JsonClass(generateAdapter = true) internal class GetPushersResponse( @Json(name = "pushers") val pushers: List? = null -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/GetPushersTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/GetPushersTask.kt index 8fd1a5b3be..045db56786 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/GetPushersTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/GetPushersTask.kt @@ -26,15 +26,15 @@ import javax.inject.Inject internal interface GetPushersTask : Task -internal class DefaultGetPusherTask @Inject constructor(private val pushersAPI: PushersAPI, - private val monarchy: Monarchy) : GetPushersTask { +internal class DefaultGetPushersTask @Inject constructor(private val pushersAPI: PushersAPI, + private val monarchy: Monarchy) : GetPushersTask { override suspend fun execute(params: Unit) { val response = executeRequest { apiCall = pushersAPI.getPushers() } monarchy.awaitTransaction { realm -> - //clear existings? + // clear existings? realm.where(PusherEntity::class.java) .findAll().deleteAllFromRealm() response.pushers?.forEach { jsonPusher -> @@ -45,4 +45,4 @@ internal class DefaultGetPusherTask @Inject constructor(private val pushersAPI: } } } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/JsonPusher.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/JsonPusher.kt index d262eeb745..8234a3b387 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/JsonPusher.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/JsonPusher.kt @@ -100,4 +100,3 @@ internal data class JsonPusher( @Json(name = "append") val append: Boolean? = false ) - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/JsonPusherData.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/JsonPusherData.kt index 95898acae2..67c13b343f 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/JsonPusherData.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/JsonPusherData.kt @@ -31,4 +31,4 @@ internal data class JsonPusherData( */ @Json(name = "format") val format: String? = null -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/PushRulesApi.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/PushRulesApi.kt index f191b21d1d..786c1c90e6 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/PushRulesApi.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/PushRulesApi.kt @@ -21,7 +21,6 @@ import im.vector.matrix.android.internal.network.NetworkConstants import retrofit2.Call import retrofit2.http.* - internal interface PushRulesApi { /** * Get all push rules @@ -42,7 +41,6 @@ internal interface PushRulesApi { @Body enable: Boolean?) : Call - /** * Update the ruleID action * @@ -56,7 +54,6 @@ internal interface PushRulesApi { @Body actions: Any) : Call - /** * Delete a rule * @@ -80,4 +77,4 @@ internal interface PushRulesApi { @Path("ruleId") ruleId: String, @Body rule: PushRule) : Call -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/PushersAPI.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/PushersAPI.kt index 7516e48a0c..9f1859548e 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/PushersAPI.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/PushersAPI.kt @@ -21,7 +21,6 @@ import retrofit2.http.Body import retrofit2.http.GET import retrofit2.http.POST - internal interface PushersAPI { /** @@ -40,5 +39,4 @@ internal interface PushersAPI { */ @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "pushers/set") fun setPusher(@Body jsonPusher: JsonPusher): Call - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/PushersModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/PushersModule.kt index 784a140b19..7aa06c0275 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/PushersModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/PushersModule.kt @@ -44,7 +44,6 @@ internal abstract class PushersModule { fun providesPushRulesApi(retrofit: Retrofit): PushRulesApi { return retrofit.create(PushRulesApi::class.java) } - } @Binds @@ -54,7 +53,7 @@ internal abstract class PushersModule { abstract fun bindConditionResolver(conditionResolver: DefaultConditionResolver): ConditionResolver @Binds - abstract fun bindGetPushersTask(getPusherTask: DefaultGetPusherTask): GetPushersTask + abstract fun bindGetPushersTask(getPushersTask: DefaultGetPushersTask): GetPushersTask @Binds abstract fun bindGetPushRulesTask(getPushRulesTask: DefaultGetPushRulesTask): GetPushRulesTask @@ -73,5 +72,4 @@ internal abstract class PushersModule { @Binds abstract fun bindProcessEventForPushTask(processEventForPushTask: DefaultProcessEventForPushTask): ProcessEventForPushTask - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/RemovePusherTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/RemovePusherTask.kt index d22447586c..297375454a 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/RemovePusherTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/RemovePusherTask.kt @@ -66,4 +66,4 @@ internal class DefaultRemovePusherTask @Inject constructor( PusherEntity.where(it, params.pushKey).findFirst()?.deleteFromRealm() } } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/SavePushRulesTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/SavePushRulesTask.kt index b658858e47..fcab627251 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/SavePushRulesTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/SavePushRulesTask.kt @@ -25,7 +25,6 @@ import im.vector.matrix.android.internal.task.Task import im.vector.matrix.android.internal.util.awaitTransaction import javax.inject.Inject - /** * Save the push rules in DB */ @@ -78,4 +77,4 @@ internal class DefaultSavePushRulesTask @Inject constructor(private val monarchy realm.insertOrUpdate(underrides) } } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/UpdatePushRuleEnableStatusTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/UpdatePushRuleEnableStatusTask.kt index f3077e6837..91ed65d833 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/UpdatePushRuleEnableStatusTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/UpdatePushRuleEnableStatusTask.kt @@ -21,7 +21,6 @@ import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.task.Task import javax.inject.Inject - internal interface UpdatePushRuleEnableStatusTask : Task { data class Params(val kind: RuleKind, val pushRule: PushRule, @@ -36,4 +35,4 @@ internal class DefaultUpdatePushRuleEnableStatusTask @Inject constructor(private apiCall = pushRulesApi.updateEnableRuleStatus(params.kind.value, params.pushRule.ruleId, params.enabled) } } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoom.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoom.kt index 6b2a6843f1..fea827fd25 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoom.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoom.kt @@ -24,12 +24,14 @@ import im.vector.matrix.android.api.session.room.Room import im.vector.matrix.android.api.session.room.members.MembershipService import im.vector.matrix.android.api.session.room.model.RoomSummary import im.vector.matrix.android.api.session.room.model.relation.RelationService +import im.vector.matrix.android.api.session.room.reporting.ReportingService import im.vector.matrix.android.api.session.room.read.ReadService import im.vector.matrix.android.api.session.room.send.DraftService import im.vector.matrix.android.api.session.room.send.SendService import im.vector.matrix.android.api.session.room.state.StateService import im.vector.matrix.android.api.session.room.timeline.TimelineService -import im.vector.matrix.android.internal.database.RealmLiveData +import im.vector.matrix.android.api.util.Optional +import im.vector.matrix.android.api.util.toOptional import im.vector.matrix.android.internal.database.mapper.RoomSummaryMapper import im.vector.matrix.android.internal.database.model.RoomSummaryEntity import im.vector.matrix.android.internal.database.model.RoomSummaryEntityFields @@ -43,32 +45,28 @@ internal class DefaultRoom @Inject constructor(override val roomId: String, private val sendService: SendService, private val draftService: DraftService, private val stateService: StateService, + private val reportingService: ReportingService, private val readService: ReadService, private val cryptoService: CryptoService, private val relationService: RelationService, - private val roomMembersService: MembershipService -) : Room, - TimelineService by timelineService, - SendService by sendService, - DraftService by draftService, - StateService by stateService, - ReadService by readService, - RelationService by relationService, - MembershipService by roomMembersService { + private val roomMembersService: MembershipService) : + Room, + TimelineService by timelineService, + SendService by sendService, + DraftService by draftService, + StateService by stateService, + ReportingService by reportingService, + ReadService by readService, + RelationService by relationService, + MembershipService by roomMembersService { - override fun liveRoomSummary(): LiveData { - val liveRealmData = RealmLiveData(monarchy.realmConfiguration) { realm -> - RoomSummaryEntity.where(realm, roomId).isNotEmpty(RoomSummaryEntityFields.DISPLAY_NAME) - } - return Transformations.map(liveRealmData) { results -> - val roomSummaries = results.map { roomSummaryMapper.map(it) } - - if (roomSummaries.isEmpty()) { - // Create a dummy RoomSummary to avoid Crash during Sign Out or clear cache - RoomSummary(roomId) - } else { - roomSummaries.first() - } + override fun getRoomSummaryLive(): LiveData> { + val liveData = monarchy.findAllMappedWithChanges( + { realm -> RoomSummaryEntity.where(realm, roomId).isNotEmpty(RoomSummaryEntityFields.DISPLAY_NAME) }, + { roomSummaryMapper.map(it) } + ) + return Transformations.map(liveData) { results -> + results.firstOrNull().toOptional() } } @@ -90,5 +88,4 @@ internal class DefaultRoom @Inject constructor(override val roomId: String, override fun shouldEncryptForInvitedMembers(): Boolean { return cryptoService.shouldEncryptForInvitedMembers(roomId) } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoomDirectoryService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoomDirectoryService.kt index 4aeace70ed..4251a66304 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoomDirectoryService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoomDirectoryService.kt @@ -59,4 +59,4 @@ internal class DefaultRoomDirectoryService @Inject constructor(private val getPu } .executeBy(taskExecutor) } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoomService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoomService.kt index bd5462b151..962b7b54d6 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoomService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoomService.kt @@ -32,6 +32,7 @@ import im.vector.matrix.android.internal.database.model.RoomSummaryEntityFields import im.vector.matrix.android.internal.database.query.where import im.vector.matrix.android.internal.session.room.create.CreateRoomTask import im.vector.matrix.android.internal.session.room.membership.joining.JoinRoomTask +import im.vector.matrix.android.internal.session.room.read.MarkAllRoomsReadTask import im.vector.matrix.android.internal.task.TaskExecutor import im.vector.matrix.android.internal.task.configureWith import io.realm.Realm @@ -41,6 +42,7 @@ internal class DefaultRoomService @Inject constructor(private val monarchy: Mona private val roomSummaryMapper: RoomSummaryMapper, private val createRoomTask: CreateRoomTask, private val joinRoomTask: JoinRoomTask, + private val markAllRoomsReadTask: MarkAllRoomsReadTask, private val roomFactory: RoomFactory, private val taskExecutor: TaskExecutor) : RoomService { @@ -80,4 +82,12 @@ internal class DefaultRoomService @Inject constructor(private val monarchy: Mona } .executeBy(taskExecutor) } -} \ No newline at end of file + + override fun markAllAsRead(roomIds: List, callback: MatrixCallback): Cancelable { + return markAllRoomsReadTask + .configureWith(MarkAllRoomsReadTask.Params(roomIds)) { + this.callback = callback + } + .executeBy(taskExecutor) + } +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/EventRelationsAggregationTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/EventRelationsAggregationTask.kt index 786ba168ac..224b3bcfeb 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/EventRelationsAggregationTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/EventRelationsAggregationTask.kt @@ -28,7 +28,6 @@ import im.vector.matrix.android.internal.database.mapper.EventMapper import im.vector.matrix.android.internal.database.model.* import im.vector.matrix.android.internal.database.query.create import im.vector.matrix.android.internal.database.query.where -import im.vector.matrix.android.internal.session.room.send.LocalEchoEventFactory import im.vector.matrix.android.internal.task.Task import im.vector.matrix.android.internal.util.awaitTransaction import io.realm.Realm @@ -50,7 +49,7 @@ internal class DefaultEventRelationsAggregationTask @Inject constructor( private val monarchy: Monarchy, private val cryptoService: CryptoService) : EventRelationsAggregationTask { - //OPT OUT serer aggregation until API mature enough + // OPT OUT serer aggregation until API mature enough private val SHOULD_HANDLE_SERVER_AGREGGATION = false override suspend fun execute(params: EventRelationsAggregationTask.Params) { @@ -65,16 +64,16 @@ internal class DefaultEventRelationsAggregationTask @Inject constructor( private fun update(realm: Realm, events: List, userId: String) { events.forEach { event -> - try { //Temporary catch, should be removed + try { // Temporary catch, should be removed val roomId = event.roomId if (roomId == null) { Timber.w("Event has no room id ${event.eventId}") return@forEach } - val isLocalEcho = LocalEchoEventFactory.isLocalEchoId(event.eventId ?: "") + val isLocalEcho = LocalEcho.isLocalEchoId(event.eventId ?: "") when (event.type) { EventType.REACTION -> { - //we got a reaction!! + // we got a reaction!! Timber.v("###REACTION in room $roomId , reaction eventID ${event.eventId}") handleReaction(event, roomId, realm, userId, isLocalEcho) } @@ -85,7 +84,7 @@ internal class DefaultEventRelationsAggregationTask @Inject constructor( EventAnnotationsSummaryEntity.where(realm, event.eventId ?: "").findFirst()?.let { - TimelineEventEntity.where(realm, eventId = event.eventId + TimelineEventEntity.where(realm, roomId = roomId, eventId = event.eventId ?: "").findFirst()?.let { tet -> tet.annotations = it } @@ -95,18 +94,16 @@ internal class DefaultEventRelationsAggregationTask @Inject constructor( val content: MessageContent? = event.content.toModel() if (content?.relatesTo?.type == RelationType.REPLACE) { Timber.v("###REPLACE in room $roomId for event ${event.eventId}") - //A replace! + // A replace! handleReplace(realm, event, content, roomId, isLocalEcho) } - - } EventType.ENCRYPTED -> { - //Relation type is in clear + // Relation type is in clear val encryptedEventContent = event.content.toModel() if (encryptedEventContent?.relatesTo?.type == RelationType.REPLACE) { - //we need to decrypt if needed + // we need to decrypt if needed if (event.mxDecryptionResult == null) { try { val result = cryptoService.decryptEvent(event, event.roomId) @@ -118,12 +115,12 @@ internal class DefaultEventRelationsAggregationTask @Inject constructor( ) } catch (e: MXCryptoError) { Timber.w("Failed to decrypt e2e replace") - //TODO -> we should keep track of this and retry, or aggregation will be broken + // TODO -> we should keep track of this and retry, or aggregation will be broken } } event.getClearContent().toModel()?.let { Timber.v("###REPLACE in room $roomId for event ${event.eventId}") - //A replace! + // A replace! handleReplace(realm, event, it, roomId, isLocalEcho, encryptedEventContent.relatesTo.eventId) } } @@ -137,12 +134,11 @@ internal class DefaultEventRelationsAggregationTask @Inject constructor( // val unsignedData = EventMapper.map(eventToPrune).unsignedData // ?: UnsignedData(null, null) - //was this event a m.replace + // was this event a m.replace val contentModel = ContentMapper.map(eventToPrune.content)?.toModel() if (RelationType.REPLACE == contentModel?.relatesTo?.type && contentModel.relatesTo?.eventId != null) { handleRedactionOfReplace(eventToPrune, contentModel.relatesTo!!.eventId!!, realm) } - } EventType.REACTION -> { handleReactionRedact(eventToPrune, realm, userId) @@ -151,31 +147,28 @@ internal class DefaultEventRelationsAggregationTask @Inject constructor( } else -> Timber.v("UnHandled event ${event.eventId}") } - } catch (t: Throwable) { Timber.e(t, "## Should not happen ") } } - } 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 - //ok, this is a replace + // ok, this is a replace var existing = EventAnnotationsSummaryEntity.where(realm, targetEventId).findFirst() if (existing == null) { Timber.v("###REPLACE creating new relation summary for $targetEventId") - existing = EventAnnotationsSummaryEntity.create(realm, targetEventId) - existing.roomId = roomId + existing = EventAnnotationsSummaryEntity.create(realm, roomId, targetEventId) } - //we have it + // we have it val existingSummary = existing.editSummary if (existingSummary == null) { - Timber.v("###REPLACE new edit summary for ${targetEventId}, creating one (localEcho:$isLocalEcho)") - //create the edit summary + Timber.v("###REPLACE new edit summary for $targetEventId, creating one (localEcho:$isLocalEcho)") + // create the edit summary val editSummary = realm.createObject(EditAggregatedSummaryEntity::class.java) editSummary.aggregatedContent = ContentMapper.map(newContent) if (isLocalEcho) { @@ -189,14 +182,14 @@ internal class DefaultEventRelationsAggregationTask @Inject constructor( existing.editSummary = editSummary } else { if (existingSummary.sourceEvents.contains(eventId)) { - //ignore this event, we already know it (??) - Timber.v("###REPLACE ignoring event for summary, it's known ${eventId}") + // ignore this event, we already know it (??) + Timber.v("###REPLACE ignoring event for summary, it's known $eventId") return } val txId = event.unsignedData?.transactionId - //is it a remote echo? + // is it a remote echo? if (!isLocalEcho && existingSummary.sourceLocalEchoEvents.contains(txId)) { - //ok it has already been managed + // ok it has already been managed Timber.v("###REPLACE Receiving remote echo of edit (edit already done)") existingSummary.sourceLocalEchoEvents.remove(txId) existingSummary.sourceEvents.add(event.eventId) @@ -206,7 +199,7 @@ internal class DefaultEventRelationsAggregationTask @Inject constructor( ) { Timber.v("###REPLACE Computing aggregated edit summary (isLocalEcho:$isLocalEcho)") if (!isLocalEcho) { - //Do not take local echo originServerTs here, could mess up ordering (keep old ts) + // Do not take local echo originServerTs here, could mess up ordering (keep old ts) existingSummary.lastEditTs = event.originServerTs ?: System.currentTimeMillis() } existingSummary.aggregatedContent = ContentMapper.map(newContent) @@ -216,14 +209,13 @@ internal class DefaultEventRelationsAggregationTask @Inject constructor( existingSummary.sourceEvents.add(eventId) } } else { - //ignore this event for the summary (back paginate) + // ignore this event for the summary (back paginate) if (!isLocalEcho) { existingSummary.sourceEvents.add(eventId) } Timber.v("###REPLACE ignoring event for summary, it's to old $eventId") } } - } private fun handleInitialAggregatedRelations(event: Event, roomId: String, aggregation: AggregatedAnnotation, realm: Realm) { @@ -233,15 +225,14 @@ internal class DefaultEventRelationsAggregationTask @Inject constructor( val eventId = event.eventId ?: "" val existing = EventAnnotationsSummaryEntity.where(realm, eventId).findFirst() if (existing == null) { - val eventSummary = EventAnnotationsSummaryEntity.create(realm, eventId) - eventSummary.roomId = roomId + val eventSummary = EventAnnotationsSummaryEntity.create(realm, roomId, eventId) val sum = realm.createObject(ReactionAggregatedSummaryEntity::class.java) sum.key = it.key - sum.firstTimestamp = event.originServerTs ?: 0 //TODO how to maintain order? + sum.firstTimestamp = event.originServerTs ?: 0 // TODO how to maintain order? sum.count = it.count eventSummary.reactionsSummary.add(sum) } else { - //TODO how to handle that + // TODO how to handle that } } } @@ -254,14 +245,14 @@ internal class DefaultEventRelationsAggregationTask @Inject constructor( Timber.e("Malformed reaction content ${event.content}") return } - //rel_type must be m.annotation + // rel_type must be m.annotation if (RelationType.ANNOTATION == content.relatesTo?.type) { val reaction = content.relatesTo.key val relatedEventID = content.relatesTo.eventId val reactionEventId = event.eventId Timber.v("Reaction $reactionEventId relates to $relatedEventID") val eventSummary = EventAnnotationsSummaryEntity.where(realm, relatedEventID).findFirst() - ?: EventAnnotationsSummaryEntity.create(realm, relatedEventID).apply { this.roomId = roomId } + ?: EventAnnotationsSummaryEntity.create(realm, roomId, relatedEventID).apply { this.roomId = roomId } var sum = eventSummary.reactionsSummary.find { it.key == reaction } val txId = event.unsignedData?.transactionId @@ -284,12 +275,11 @@ internal class DefaultEventRelationsAggregationTask @Inject constructor( sum.addedByMe = sum.addedByMe || (userId == event.senderId) eventSummary.reactionsSummary.add(sum) } else { - //is this a known event (is possible? pagination?) + // is this a known event (is possible? pagination?) if (!sum.sourceEvents.contains(reactionEventId)) { - - //check if it's not the sync of a local echo + // check if it's not the sync of a local echo if (!isLocalEcho && sum.sourceLocalEcho.contains(txId)) { - //ok it has already been counted, just sync the list, do not touch count + // ok it has already been counted, just sync the list, do not touch count Timber.v("Ignoring synced of local echo for reaction $reaction") sum.sourceLocalEcho.remove(txId) sum.sourceEvents.add(reactionEventId) @@ -305,14 +295,11 @@ internal class DefaultEventRelationsAggregationTask @Inject constructor( sum.addedByMe = sum.addedByMe || (userId == event.senderId) } - } } - } else { Timber.e("Unknwon relation type ${content.relatesTo?.type} for event ${event.eventId}") } - } /** @@ -331,29 +318,28 @@ internal class DefaultEventRelationsAggregationTask @Inject constructor( Timber.w("Redaction of a replace that was not known in aggregation $sourceToDiscard") return } - //Need to remove this event from the redaction list and compute new aggregation state + // Need to remove this event from the redaction list and compute new aggregation state sourceEvents.removeAt(sourceToDiscard) val previousEdit = sourceEvents.mapNotNull { EventEntity.where(realm, it).findFirst() }.sortedBy { it.originServerTs }.lastOrNull() if (previousEdit == null) { - //revert to original + // revert to original eventSummary.editSummary?.deleteFromRealm() } else { - //I have the last event + // I have the last event ContentMapper.map(previousEdit.content)?.toModel()?.newContent?.let { newContent -> eventSummary.editSummary?.lastEditTs = previousEdit.originServerTs ?: System.currentTimeMillis() eventSummary.editSummary?.aggregatedContent = ContentMapper.map(newContent) } ?: run { Timber.e("Failed to udate edited summary") - //TODO how to reccover that + // TODO how to reccover that } - } } fun handleReactionRedact(eventToPrune: EventEntity, realm: Realm, userId: String) { Timber.v("REDACTION of reaction ${eventToPrune.eventId}") - //delete a reaction, need to update the annotation summary if any + // delete a reaction, need to update the annotation summary if any val reactionContent: ReactionContent = EventMapper.map(eventToPrune).content.toModel() ?: return val eventThatWasReacted = reactionContent.relatesTo?.eventId ?: return @@ -373,11 +359,11 @@ internal class DefaultEventRelationsAggregationTask @Inject constructor( Timber.v("Known reactions after ${aggregation.sourceEvents.joinToString(",")}") aggregation.count = aggregation.count - 1 if (eventToPrune.sender == userId) { - //Was it a redact on my reaction? + // Was it a redact on my reaction? aggregation.addedByMe = false } if (aggregation.count == 0) { - //delete! + // delete! aggregation.deleteFromRealm() } } else { @@ -388,4 +374,4 @@ internal class DefaultEventRelationsAggregationTask @Inject constructor( Timber.e("## Cannot find summary for key $reactionKey") } } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/EventRelationsAggregationUpdater.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/EventRelationsAggregationUpdater.kt index 97bbe62b11..aadf1bfccf 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/EventRelationsAggregationUpdater.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/EventRelationsAggregationUpdater.kt @@ -65,6 +65,4 @@ internal class EventRelationsAggregationUpdater @Inject constructor(@SessionData ) task.configureWith(params).executeBy(taskExecutor) } - } - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomAPI.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomAPI.kt index 0a5dcea3cb..797dbed31c 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomAPI.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomAPI.kt @@ -27,6 +27,7 @@ import im.vector.matrix.android.internal.network.NetworkConstants import im.vector.matrix.android.internal.session.room.membership.RoomMembersResponse import im.vector.matrix.android.internal.session.room.membership.joining.InviteBody import im.vector.matrix.android.internal.session.room.relation.RelationsResponse +import im.vector.matrix.android.internal.session.room.reporting.ReportContentBody import im.vector.matrix.android.internal.session.room.send.SendResponse import im.vector.matrix.android.internal.session.room.timeline.EventContextResponse import im.vector.matrix.android.internal.session.room.timeline.PaginationResponse @@ -80,7 +81,6 @@ internal interface RoomAPI { @Query("filter") filter: String? ): Call - /** * Get all members of a room * @@ -96,7 +96,6 @@ internal interface RoomAPI { @Query("not_membership") notMembership: String? ): Call - /** * Send an event to a room. * @@ -196,7 +195,6 @@ internal interface RoomAPI { @Body content: Content? ): Call - /** * Paginate relations for event based in normal topological order * @@ -248,4 +246,16 @@ internal interface RoomAPI { @Path("eventId") parent_id: String, @Body reason: Map ): Call -} \ No newline at end of file + + /** + * Reports an event as inappropriate to the server, which may then notify the appropriate people. + * + * @param roomId the room id + * @param eventId the event to report content + * @param body body containing score and reason + */ + @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/report/{eventId}") + fun reportContent(@Path("roomId") roomId: String, + @Path("eventId") eventId: String, + @Body body: ReportContentBody): Call +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomFactory.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomFactory.kt index e972f6a98e..e2199782f4 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomFactory.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomFactory.kt @@ -24,12 +24,12 @@ import im.vector.matrix.android.internal.session.room.draft.DefaultDraftService import im.vector.matrix.android.internal.session.room.membership.DefaultMembershipService import im.vector.matrix.android.internal.session.room.read.DefaultReadService import im.vector.matrix.android.internal.session.room.relation.DefaultRelationService +import im.vector.matrix.android.internal.session.room.reporting.DefaultReportingService import im.vector.matrix.android.internal.session.room.send.DefaultSendService import im.vector.matrix.android.internal.session.room.state.DefaultStateService import im.vector.matrix.android.internal.session.room.timeline.DefaultTimelineService import javax.inject.Inject - internal interface RoomFactory { fun create(roomId: String): Room } @@ -41,6 +41,7 @@ internal class DefaultRoomFactory @Inject constructor(private val monarchy: Mona private val sendServiceFactory: DefaultSendService.Factory, private val draftServiceFactory: DefaultDraftService.Factory, private val stateServiceFactory: DefaultStateService.Factory, + private val reportingServiceFactory: DefaultReportingService.Factory, private val readServiceFactory: DefaultReadService.Factory, private val relationServiceFactory: DefaultRelationService.Factory, private val membershipServiceFactory: DefaultMembershipService.Factory) : @@ -55,11 +56,11 @@ internal class DefaultRoomFactory @Inject constructor(private val monarchy: Mona sendServiceFactory.create(roomId), draftServiceFactory.create(roomId), stateServiceFactory.create(roomId), + reportingServiceFactory.create(roomId), readServiceFactory.create(roomId), cryptoService, relationServiceFactory.create(roomId), membershipServiceFactory.create(roomId) ) } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomModule.kt index 572e03d0d6..1aca492b94 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomModule.kt @@ -40,20 +40,16 @@ import im.vector.matrix.android.internal.session.room.membership.leaving.Default import im.vector.matrix.android.internal.session.room.membership.leaving.LeaveRoomTask import im.vector.matrix.android.internal.session.room.prune.DefaultPruneEventTask import im.vector.matrix.android.internal.session.room.prune.PruneEventTask +import im.vector.matrix.android.internal.session.room.read.DefaultMarkAllRoomsReadTask import im.vector.matrix.android.internal.session.room.read.DefaultSetReadMarkersTask +import im.vector.matrix.android.internal.session.room.read.MarkAllRoomsReadTask import im.vector.matrix.android.internal.session.room.read.SetReadMarkersTask -import im.vector.matrix.android.internal.session.room.relation.DefaultFetchEditHistoryTask -import im.vector.matrix.android.internal.session.room.relation.DefaultFindReactionEventForUndoTask -import im.vector.matrix.android.internal.session.room.relation.DefaultUpdateQuickReactionTask -import im.vector.matrix.android.internal.session.room.relation.FetchEditHistoryTask -import im.vector.matrix.android.internal.session.room.relation.FindReactionEventForUndoTask -import im.vector.matrix.android.internal.session.room.relation.UpdateQuickReactionTask +import im.vector.matrix.android.internal.session.room.relation.* +import im.vector.matrix.android.internal.session.room.reporting.DefaultReportContentTask +import im.vector.matrix.android.internal.session.room.reporting.ReportContentTask import im.vector.matrix.android.internal.session.room.state.DefaultSendStateTask import im.vector.matrix.android.internal.session.room.state.SendStateTask -import im.vector.matrix.android.internal.session.room.timeline.DefaultGetContextOfEventTask -import im.vector.matrix.android.internal.session.room.timeline.DefaultPaginationTask -import im.vector.matrix.android.internal.session.room.timeline.GetContextOfEventTask -import im.vector.matrix.android.internal.session.room.timeline.PaginationTask +import im.vector.matrix.android.internal.session.room.timeline.* import retrofit2.Retrofit @Module @@ -108,6 +104,9 @@ internal abstract class RoomModule { @Binds abstract fun bindSetReadMarkersTask(setReadMarkersTask: DefaultSetReadMarkersTask): SetReadMarkersTask + @Binds + abstract fun bindMarkAllRoomsReadTask(markAllRoomsReadTask: DefaultMarkAllRoomsReadTask): MarkAllRoomsReadTask + @Binds abstract fun bindFindReactionEventForUndoTask(findReactionEventForUndoTask: DefaultFindReactionEventForUndoTask): FindReactionEventForUndoTask @@ -117,9 +116,15 @@ internal abstract class RoomModule { @Binds abstract fun bindSendStateTask(sendStateTask: DefaultSendStateTask): SendStateTask + @Binds + abstract fun bindReportContentTask(reportContentTask: DefaultReportContentTask): ReportContentTask + @Binds abstract fun bindGetContextOfEventTask(getContextOfEventTask: DefaultGetContextOfEventTask): GetContextOfEventTask + @Binds + abstract fun bindClearUnlinkedEventsTask(clearUnlinkedEventsTask: DefaultClearUnlinkedEventsTask): ClearUnlinkedEventsTask + @Binds abstract fun bindPaginationTask(paginationTask: DefaultPaginationTask): PaginationTask @@ -127,5 +132,5 @@ internal abstract class RoomModule { abstract fun bindFileService(fileService: DefaultFileService): FileService @Binds - abstract fun bindFetchEditHistoryTask(editHistoryTask: DefaultFetchEditHistoryTask): FetchEditHistoryTask + abstract fun bindFetchEditHistoryTask(fetchEditHistoryTask: DefaultFetchEditHistoryTask): FetchEditHistoryTask } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomSummaryUpdater.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomSummaryUpdater.kt index f92f2ccc1e..0d28720ec6 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomSummaryUpdater.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomSummaryUpdater.kt @@ -87,11 +87,11 @@ internal class RoomSummaryUpdater @Inject constructor(@UserId private val userId roomSummaryEntity.membership = membership } - val latestPreviewableEvent = TimelineEventEntity.latestEvent(realm, roomId, includesSending = true, includedTypes = PREVIEWABLE_TYPES) + val latestPreviewableEvent = TimelineEventEntity.latestEvent(realm, roomId, includesSending = true, filterTypes = PREVIEWABLE_TYPES) val lastTopicEvent = EventEntity.where(realm, roomId, EventType.STATE_ROOM_TOPIC).prev()?.asDomain() roomSummaryEntity.hasUnreadMessages = roomSummaryEntity.notificationCount > 0 - //avoid this call if we are sure there are unread events + // avoid this call if we are sure there are unread events || !isEventRead(monarchy, userId, roomId, latestPreviewableEvent?.eventId) val otherRoomMembers = RoomMembers(realm, roomId) @@ -108,4 +108,4 @@ internal class RoomSummaryUpdater @Inject constructor(@UserId private val userId roomSummaryEntity.otherMemberIds.clear() roomSummaryEntity.otherMemberIds.addAll(otherRoomMembers) } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/create/CreateRoomTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/create/CreateRoomTask.kt index 93c2eb0b11..ca86765cd9 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/create/CreateRoomTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/create/CreateRoomTask.kt @@ -47,7 +47,6 @@ internal class DefaultCreateRoomTask @Inject constructor(private val roomAPI: Ro @SessionDatabase private val realmConfiguration: RealmConfiguration) : CreateRoomTask { - override suspend fun execute(params: CreateRoomParams): String { val createRoomResponse = executeRequest { apiCall = roomAPI.createRoom(params) @@ -88,5 +87,4 @@ internal class DefaultCreateRoomTask @Inject constructor(private val roomAPI: Ro val setReadMarkerParams = SetReadMarkersTask.Params(roomId, markAllAsRead = true) return readMarkersTask.execute(setReadMarkerParams) } - } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/create/RoomCreateEventLiveObserver.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/create/RoomCreateEventLiveObserver.kt index 1bc6b9658e..010023596c 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/create/RoomCreateEventLiveObserver.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/create/RoomCreateEventLiveObserver.kt @@ -65,9 +65,7 @@ internal class RoomCreateEventLiveObserver @Inject constructor(@SessionDatabase ?: RoomSummaryEntity(predecessorRoomId) predecessorRoomSummary.versioningState = VersioningState.UPGRADED_ROOM_JOINED realm.insertOrUpdate(predecessorRoomSummary) - } } } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/draft/DefaultDraftService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/draft/DefaultDraftService.kt index c5676f84c8..9fd9cf7c9d 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/draft/DefaultDraftService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/draft/DefaultDraftService.kt @@ -24,7 +24,6 @@ import com.zhuinden.monarchy.Monarchy import im.vector.matrix.android.BuildConfig import im.vector.matrix.android.api.session.room.send.DraftService import im.vector.matrix.android.api.session.room.send.UserDraft -import im.vector.matrix.android.internal.database.RealmLiveData import im.vector.matrix.android.internal.database.mapper.DraftMapper import im.vector.matrix.android.internal.database.model.DraftEntity import im.vector.matrix.android.internal.database.model.RoomSummaryEntity @@ -51,12 +50,13 @@ internal class DefaultDraftService @AssistedInject constructor(@Assisted private monarchy.writeAsync { realm -> - val roomSummaryEntity = RoomSummaryEntity.where(realm, roomId).findFirst() ?: realm.createObject(roomId) + val roomSummaryEntity = RoomSummaryEntity.where(realm, roomId).findFirst() + ?: realm.createObject(roomId) val userDraftsEntity = roomSummaryEntity.userDrafts - ?: realm.createObject().also { - roomSummaryEntity.userDrafts = it - } + ?: realm.createObject().also { + roomSummaryEntity.userDrafts = it + } userDraftsEntity.let { userDraftEntity -> // Save only valid draft @@ -150,17 +150,16 @@ internal class DefaultDraftService @AssistedInject constructor(@Assisted private } override fun getDraftsLive(): LiveData> { - val liveData = RealmLiveData(monarchy.realmConfiguration) { - UserDraftsEntity.where(it, roomId) - } - - return Transformations.map(liveData) { userDraftsEntities -> - userDraftsEntities.firstOrNull()?.let { userDraftEntity -> - userDraftEntity.userDrafts.map { draftEntity -> - DraftMapper.map(draftEntity) + val liveData = monarchy.findAllMappedWithChanges( + { UserDraftsEntity.where(it, roomId) }, + { + it.userDrafts.map { draft -> + DraftMapper.map(draft) + } } - } ?: emptyList() + ) + return Transformations.map(liveData) { + it.firstOrNull() ?: emptyList() } } } - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/DefaultMembershipService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/DefaultMembershipService.kt index a1aac0ae36..3490fed30f 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/DefaultMembershipService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/DefaultMembershipService.kt @@ -109,4 +109,4 @@ internal class DefaultMembershipService @AssistedInject constructor(@Assisted pr } .executeBy(taskExecutor) } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/LoadRoomMembersTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/LoadRoomMembersTask.kt index 709e8da973..d952915d2c 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/LoadRoomMembersTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/LoadRoomMembersTask.kt @@ -64,7 +64,6 @@ internal class DefaultLoadRoomMembersTask @Inject constructor(private val roomAP val roomEntity = RoomEntity.where(realm, roomId).findFirst() ?: realm.createObject(roomId) - for (roomMemberEvent in response.roomMemberEvents) { roomEntity.addStateEvent(roomMemberEvent) UserEntityFactory.createOrNull(roomMemberEvent)?.also { @@ -84,5 +83,4 @@ internal class DefaultLoadRoomMembersTask @Inject constructor(private val roomAP RoomEntity.where(it, roomId).findFirst()?.areAllMembersLoaded ?: false } } - } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/RoomDisplayNameResolver.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/RoomDisplayNameResolver.kt index 37adba0df8..965bd21cf4 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/RoomDisplayNameResolver.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/RoomDisplayNameResolver.kt @@ -77,7 +77,6 @@ internal class RoomDisplayNameResolver @Inject constructor(private val context: val roomMembers = RoomMembers(realm, roomId) val loadedMembers = roomMembers.queryRoomMembersEvent().findAll() - if (roomEntity?.membership == Membership.INVITE) { val inviteMeEvent = roomMembers.queryRoomMemberEvent(userId).findFirst() val inviterId = inviteMeEvent?.sender diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/RoomMembers.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/RoomMembers.kt index 8db3f170ea..b50424b343 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/RoomMembers.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/RoomMembers.kt @@ -132,10 +132,8 @@ internal class RoomMembers(private val realm: Realm, .findAll() .map { it.asDomain() } .associateBy { it.stateKey!! } - .mapValues { it.value.content.toModel()!! } - .filterValues { predicate(it) } + .filterValues { predicate(it.content.toModel()!!) } .keys .toList() } - } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/RoomMembersResponse.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/RoomMembersResponse.kt index af3bf9b680..7f77fbf79c 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/RoomMembersResponse.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/RoomMembersResponse.kt @@ -23,4 +23,4 @@ import im.vector.matrix.android.api.session.events.model.Event @JsonClass(generateAdapter = true) internal data class RoomMembersResponse( @Json(name = "chunk") val roomMemberEvents: List -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/joining/InviteTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/joining/InviteTask.kt index 68d72c6b84..a41e8d3ca3 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/joining/InviteTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/joining/InviteTask.kt @@ -21,7 +21,6 @@ import im.vector.matrix.android.internal.session.room.RoomAPI import im.vector.matrix.android.internal.task.Task import javax.inject.Inject - internal interface InviteTask : Task { data class Params( val roomId: String, diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/joining/JoinRoomTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/joining/JoinRoomTask.kt index 5ca23a0d2d..2555d80209 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/joining/JoinRoomTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/joining/JoinRoomTask.kt @@ -63,5 +63,4 @@ internal class DefaultJoinRoomTask @Inject constructor(private val roomAPI: Room val setReadMarkerParams = SetReadMarkersTask.Params(roomId, markAllAsRead = true) readMarkersTask.execute(setReadMarkerParams) } - } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/leaving/LeaveRoomTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/leaving/LeaveRoomTask.kt index d4ff169c73..be9a421e95 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/leaving/LeaveRoomTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/leaving/LeaveRoomTask.kt @@ -34,5 +34,4 @@ internal class DefaultLeaveRoomTask @Inject constructor(private val roomAPI: Roo apiCall = roomAPI.leave(params.roomId, HashMap()) } } - } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/prune/EventsPruner.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/prune/EventsPruner.kt index ac3c7a4e22..d66a2f6e57 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/prune/EventsPruner.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/prune/EventsPruner.kt @@ -23,7 +23,6 @@ import im.vector.matrix.android.internal.database.mapper.asDomain import im.vector.matrix.android.internal.database.model.EventEntity import im.vector.matrix.android.internal.database.query.types import im.vector.matrix.android.internal.di.SessionDatabase -import im.vector.matrix.android.internal.di.UserId import im.vector.matrix.android.internal.task.TaskExecutor import im.vector.matrix.android.internal.task.configureWith import io.realm.OrderedCollectionChangeSet @@ -37,7 +36,6 @@ import javax.inject.Inject * As it will actually delete the content, it should be called last in the list of listener. */ internal class EventsPruner @Inject constructor(@SessionDatabase realmConfiguration: RealmConfiguration, - @UserId private val userId: String, private val pruneEventTask: PruneEventTask, private val taskExecutor: TaskExecutor) : RealmLiveEntityObserver(realmConfiguration) { @@ -52,11 +50,7 @@ internal class EventsPruner @Inject constructor(@SessionDatabase realmConfigurat .mapNotNull { results[it]?.asDomain() } .toList() - val params = PruneEventTask.Params( - insertedDomains, - userId - ) + val params = PruneEventTask.Params(insertedDomains) pruneEventTask.configureWith(params).executeBy(taskExecutor) } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/prune/PruneEventTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/prune/PruneEventTask.kt index 35df20df78..c303e1c215 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/prune/PruneEventTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/prune/PruneEventTask.kt @@ -18,6 +18,7 @@ package im.vector.matrix.android.internal.session.room.prune import com.zhuinden.monarchy.Monarchy import im.vector.matrix.android.api.session.events.model.Event import im.vector.matrix.android.api.session.events.model.EventType +import im.vector.matrix.android.api.session.events.model.LocalEcho import im.vector.matrix.android.api.session.events.model.UnsignedData import im.vector.matrix.android.internal.database.helper.updateSenderData import im.vector.matrix.android.internal.database.mapper.ContentMapper @@ -27,21 +28,17 @@ import im.vector.matrix.android.internal.database.model.TimelineEventEntity import im.vector.matrix.android.internal.database.query.findWithSenderMembershipEvent import im.vector.matrix.android.internal.database.query.where import im.vector.matrix.android.internal.di.MoshiProvider -import im.vector.matrix.android.internal.session.room.send.LocalEchoEventFactory import im.vector.matrix.android.internal.task.Task import im.vector.matrix.android.internal.util.awaitTransaction import io.realm.Realm import timber.log.Timber import javax.inject.Inject - internal interface PruneEventTask : Task { data class Params( - val redactionEvents: List, - val userId: String + val redactionEvents: List ) - } internal class DefaultPruneEventTask @Inject constructor(private val monarchy: Monarchy) : PruneEventTask { @@ -49,20 +46,20 @@ internal class DefaultPruneEventTask @Inject constructor(private val monarchy: M override suspend fun execute(params: PruneEventTask.Params) { monarchy.awaitTransaction { realm -> params.redactionEvents.forEach { event -> - pruneEvent(realm, event, params.userId) + pruneEvent(realm, event) } } } - private fun pruneEvent(realm: Realm, redactionEvent: Event, userId: String) { + private fun pruneEvent(realm: Realm, redactionEvent: Event) { if (redactionEvent.redacts.isNullOrBlank()) { return } - val redactionEventEntity = EventEntity.where(realm, eventId = redactionEvent.eventId - ?: "").findFirst() - ?: return - val isLocalEcho = LocalEchoEventFactory.isLocalEchoId(redactionEvent.eventId ?: "") + // Check that we know this event + EventEntity.where(realm, eventId = redactionEvent.eventId ?: "").findFirst() ?: return + + val isLocalEcho = LocalEcho.isLocalEchoId(redactionEvent.eventId ?: "") Timber.v("Redact event for ${redactionEvent.redacts} localEcho=$isLocalEcho") val eventToPrune = EventEntity.where(realm, eventId = redactionEvent.redacts).findFirst() @@ -80,7 +77,7 @@ internal class DefaultPruneEventTask @Inject constructor(private val monarchy: M val unsignedData = EventMapper.map(eventToPrune).unsignedData ?: UnsignedData(null, null) - //was this event a m.replace + // was this event a m.replace // val contentModel = ContentMapper.map(eventToPrune.content)?.toModel() // if (RelationType.REPLACE == contentModel?.relatesTo?.type && contentModel.relatesTo?.eventId != null) { // eventRelationsAggregationUpdater.handleRedactionOfReplace(eventToPrune, contentModel.relatesTo!!.eventId!!, realm) @@ -91,7 +88,6 @@ internal class DefaultPruneEventTask @Inject constructor(private val monarchy: M eventToPrune.unsignedData = MoshiProvider.providesMoshi().adapter(UnsignedData::class.java).toJson(modified) eventToPrune.decryptionResultJson = null eventToPrune.decryptionErrorCode = null - } // EventType.REACTION -> { // eventRelationsAggregationUpdater.handleReactionRedact(eventToPrune, realm, userId) @@ -106,7 +102,6 @@ internal class DefaultPruneEventTask @Inject constructor(private val monarchy: M } } - private fun computeAllowedKeys(type: String): List { // Add filtered content, allowed keys in content depends on the event type return when (type) { @@ -128,4 +123,4 @@ internal class DefaultPruneEventTask @Inject constructor(private val monarchy: M else -> emptyList() } } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/read/DefaultReadService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/read/DefaultReadService.kt index 67182e1501..b8b9fe82ef 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/read/DefaultReadService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/read/DefaultReadService.kt @@ -24,8 +24,11 @@ import com.zhuinden.monarchy.Monarchy import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.session.room.model.ReadReceipt import im.vector.matrix.android.api.session.room.read.ReadService -import im.vector.matrix.android.internal.database.RealmLiveData +import im.vector.matrix.android.api.util.Optional +import im.vector.matrix.android.api.util.toOptional import im.vector.matrix.android.internal.database.mapper.ReadReceiptsSummaryMapper +import im.vector.matrix.android.internal.database.model.ReadMarkerEntity +import im.vector.matrix.android.internal.database.model.ReadReceiptEntity import im.vector.matrix.android.internal.database.model.ReadReceiptsSummaryEntity import im.vector.matrix.android.internal.database.query.isEventRead import im.vector.matrix.android.internal.database.query.where @@ -73,21 +76,37 @@ internal class DefaultReadService @AssistedInject constructor(@Assisted private .executeBy(taskExecutor) } - override fun isEventRead(eventId: String): Boolean { return isEventRead(monarchy, userId, roomId, eventId) } - override fun getEventReadReceiptsLive(eventId: String): LiveData> { - val liveEntity = RealmLiveData(monarchy.realmConfiguration) { realm -> - ReadReceiptsSummaryEntity.where(realm, eventId) - } - return Transformations.map(liveEntity) { realmResults -> - realmResults.firstOrNull()?.let { - readReceiptsSummaryMapper.map(it) - }?.sortedByDescending { - it.originServerTs - } ?: emptyList() + override fun getReadMarkerLive(): LiveData> { + val liveRealmData = monarchy.findAllMappedWithChanges( + { ReadMarkerEntity.where(it, roomId) }, + { it.eventId } + ) + return Transformations.map(liveRealmData) { + it.firstOrNull().toOptional() } } -} \ No newline at end of file + + override fun getMyReadReceiptLive(): LiveData> { + val liveRealmData = monarchy.findAllMappedWithChanges( + { ReadReceiptEntity.where(it, roomId = roomId, userId = userId) }, + { it.eventId } + ) + return Transformations.map(liveRealmData) { + it.firstOrNull().toOptional() + } + } + + override fun getEventReadReceiptsLive(eventId: String): LiveData> { + val liveRealmData = monarchy.findAllMappedWithChanges( + { ReadReceiptsSummaryEntity.where(it, eventId) }, + { readReceiptsSummaryMapper.map(it) } + ) + return Transformations.map(liveRealmData) { + it.firstOrNull() ?: emptyList() + } + } +} diff --git a/vector/src/main/java/im/vector/riotx/core/dialogs/DialogCallAdapter.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/read/FullyReadContent.kt similarity index 70% rename from vector/src/main/java/im/vector/riotx/core/dialogs/DialogCallAdapter.kt rename to matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/read/FullyReadContent.kt index 0b0499a637..c91b2af1ae 100644 --- a/vector/src/main/java/im/vector/riotx/core/dialogs/DialogCallAdapter.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/read/FullyReadContent.kt @@ -14,14 +14,12 @@ * limitations under the License. */ -package im.vector.riotx.core.dialogs +package im.vector.matrix.android.internal.session.room.read -import android.content.Context +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass -internal class DialogCallAdapter(context: Context) : DialogAdapter(context) { - - init { - add(DialogListItem.StartVoiceCall) - add(DialogListItem.StartVideoCall) - } -} +@JsonClass(generateAdapter = true) +data class FullyReadContent( + @Json(name = "event_id") val eventId: String +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/read/MarkAllRoomsReadTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/read/MarkAllRoomsReadTask.kt new file mode 100644 index 0000000000..99376a981a --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/read/MarkAllRoomsReadTask.kt @@ -0,0 +1,35 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.matrix.android.internal.session.room.read + +import im.vector.matrix.android.internal.task.Task +import javax.inject.Inject + +internal interface MarkAllRoomsReadTask : Task { + data class Params( + val roomIds: List + ) +} + +internal class DefaultMarkAllRoomsReadTask @Inject constructor(private val readMarkersTask: SetReadMarkersTask) : MarkAllRoomsReadTask { + + override suspend fun execute(params: MarkAllRoomsReadTask.Params) { + params.roomIds.forEach { roomId -> + readMarkersTask.execute(SetReadMarkersTask.Params(roomId, markAllAsRead = true)) + } + } +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/read/SetReadMarkersTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/read/SetReadMarkersTask.kt index ac4712943d..7e5de176bb 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/read/SetReadMarkersTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/read/SetReadMarkersTask.kt @@ -17,19 +17,20 @@ package im.vector.matrix.android.internal.session.room.read import com.zhuinden.monarchy.Monarchy -import im.vector.matrix.android.internal.database.model.ChunkEntity -import im.vector.matrix.android.internal.database.model.ReadReceiptEntity +import im.vector.matrix.android.api.session.events.model.LocalEcho +import im.vector.matrix.android.internal.database.model.ReadMarkerEntity import im.vector.matrix.android.internal.database.model.RoomSummaryEntity import im.vector.matrix.android.internal.database.model.TimelineEventEntity -import im.vector.matrix.android.internal.database.query.find -import im.vector.matrix.android.internal.database.query.findLastLiveChunkFromRoom +import im.vector.matrix.android.internal.database.query.* import im.vector.matrix.android.internal.database.query.latestEvent import im.vector.matrix.android.internal.database.query.where import im.vector.matrix.android.internal.di.UserId import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.session.room.RoomAPI -import im.vector.matrix.android.internal.session.room.send.LocalEchoEventFactory +import im.vector.matrix.android.internal.session.sync.ReadReceiptHandler +import im.vector.matrix.android.internal.session.sync.RoomFullyReadHandler import im.vector.matrix.android.internal.task.Task +import im.vector.matrix.android.internal.util.awaitTransaction import io.realm.Realm import timber.log.Timber import javax.inject.Inject @@ -48,15 +49,18 @@ private const val READ_MARKER = "m.fully_read" private const val READ_RECEIPT = "m.read" internal class DefaultSetReadMarkersTask @Inject constructor(private val roomAPI: RoomAPI, - @UserId private val userId: String, - private val monarchy: Monarchy -) : SetReadMarkersTask { + private val monarchy: Monarchy, + private val roomFullyReadHandler: RoomFullyReadHandler, + private val readReceiptHandler: ReadReceiptHandler, + @UserId private val userId: String) + : SetReadMarkersTask { override suspend fun execute(params: SetReadMarkersTask.Params) { val markers = HashMap() val fullyReadEventId: String? val readReceiptEventId: String? + Timber.v("Execute set read marker with params: $params") if (params.markAllAsRead) { val latestSyncedEventId = Realm.getInstance(monarchy.realmConfiguration).use { realm -> TimelineEventEntity.latestEvent(realm, roomId = params.roomId, includesSending = false)?.eventId @@ -68,58 +72,62 @@ internal class DefaultSetReadMarkersTask @Inject constructor(private val roomAPI readReceiptEventId = params.readReceiptEventId } - if (fullyReadEventId != null) { - if (LocalEchoEventFactory.isLocalEchoId(fullyReadEventId)) { - Timber.w("Can't set read marker for local event ${params.fullyReadEventId}") + if (fullyReadEventId != null && isReadMarkerMoreRecent(params.roomId, fullyReadEventId)) { + if (LocalEcho.isLocalEchoId(fullyReadEventId)) { + Timber.w("Can't set read marker for local event $fullyReadEventId") } else { markers[READ_MARKER] = fullyReadEventId } } - if (readReceiptEventId != null - && !isEventRead(params.roomId, readReceiptEventId)) { - if (LocalEchoEventFactory.isLocalEchoId(readReceiptEventId)) { - Timber.w("Can't set read receipt for local event ${params.fullyReadEventId}") + if (readReceiptEventId != null + && !isEventRead(monarchy, userId, params.roomId, readReceiptEventId)) { + if (LocalEcho.isLocalEchoId(readReceiptEventId)) { + Timber.w("Can't set read receipt for local event $readReceiptEventId") } else { - updateNotificationCountIfNecessary(params.roomId, readReceiptEventId) markers[READ_RECEIPT] = readReceiptEventId } } if (markers.isEmpty()) { return } + updateDatabase(params.roomId, markers) executeRequest { apiCall = roomAPI.sendReadMarker(params.roomId, markers) } } - private fun updateNotificationCountIfNecessary(roomId: String, eventId: String) { - monarchy.writeAsync { realm -> - val isLatestReceived = TimelineEventEntity.latestEvent(realm, roomId = roomId, includesSending = false)?.eventId == eventId - if (isLatestReceived) { - val roomSummary = RoomSummaryEntity.where(realm, roomId).findFirst() - ?: return@writeAsync - roomSummary.notificationCount = 0 - roomSummary.highlightCount = 0 - roomSummary.hasUnreadMessages = false + private suspend fun updateDatabase(roomId: String, markers: HashMap) { + monarchy.awaitTransaction { realm -> + val readMarkerId = markers[READ_MARKER] + val readReceiptId = markers[READ_RECEIPT] + if (readMarkerId != null) { + roomFullyReadHandler.handle(realm, roomId, FullyReadContent(readMarkerId)) + } + if (readReceiptId != null) { + val readReceiptContent = ReadReceiptHandler.createContent(userId, readReceiptId) + readReceiptHandler.handle(realm, roomId, readReceiptContent, false) + val isLatestReceived = TimelineEventEntity.latestEvent(realm, roomId = roomId, includesSending = false)?.eventId == readReceiptId + if (isLatestReceived) { + val roomSummary = RoomSummaryEntity.where(realm, roomId).findFirst() + ?: return@awaitTransaction + roomSummary.notificationCount = 0 + roomSummary.highlightCount = 0 + roomSummary.hasUnreadMessages = false + } } } } - private fun isEventRead(roomId: String, eventId: String): Boolean { - var isEventRead = false - monarchy.doWithRealm { - val readReceipt = ReadReceiptEntity.where(it, roomId, userId).findFirst() - ?: return@doWithRealm - val liveChunk = ChunkEntity.findLastLiveChunkFromRoom(it, roomId) - ?: return@doWithRealm - val readReceiptIndex = liveChunk.timelineEvents.find(readReceipt.eventId)?.root?.displayIndex - ?: Int.MIN_VALUE - val eventToCheckIndex = liveChunk.timelineEvents.find(eventId)?.root?.displayIndex - ?: Int.MAX_VALUE - isEventRead = eventToCheckIndex <= readReceiptIndex + private fun isReadMarkerMoreRecent(roomId: String, newReadMarkerId: String): Boolean { + return Realm.getInstance(monarchy.realmConfiguration).use { realm -> + val currentReadMarkerId = ReadMarkerEntity.where(realm, roomId = roomId).findFirst()?.eventId + ?: return true + val readMarkerEvent = TimelineEventEntity.where(realm, roomId = roomId, eventId = currentReadMarkerId).findFirst() + val newReadMarkerEvent = TimelineEventEntity.where(realm, roomId = roomId, eventId = newReadMarkerId).findFirst() + val currentReadMarkerIndex = readMarkerEvent?.root?.displayIndex ?: Int.MAX_VALUE + val newReadMarkerIndex = newReadMarkerEvent?.root?.displayIndex ?: Int.MIN_VALUE + newReadMarkerIndex > currentReadMarkerIndex } - return isEventRead } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/relation/DefaultRelationService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/relation/DefaultRelationService.kt index a1abc94f29..11be821d7e 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/relation/DefaultRelationService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/relation/DefaultRelationService.kt @@ -30,11 +30,10 @@ import im.vector.matrix.android.api.session.room.model.message.MessageType import im.vector.matrix.android.api.session.room.model.relation.RelationService import im.vector.matrix.android.api.session.room.timeline.TimelineEvent import im.vector.matrix.android.api.util.Cancelable -import im.vector.matrix.android.internal.database.RealmLiveData -import im.vector.matrix.android.internal.database.helper.addSendingEvent +import im.vector.matrix.android.api.util.Optional +import im.vector.matrix.android.api.util.toOptional import im.vector.matrix.android.internal.database.mapper.asDomain import im.vector.matrix.android.internal.database.model.EventAnnotationsSummaryEntity -import im.vector.matrix.android.internal.database.model.RoomEntity import im.vector.matrix.android.internal.database.query.where import im.vector.matrix.android.internal.di.UserId import im.vector.matrix.android.internal.session.room.send.EncryptEventWorker @@ -64,43 +63,37 @@ internal class DefaultRelationService @AssistedInject constructor(@Assisted priv fun create(roomId: String): RelationService } - override fun sendReaction(reaction: String, targetEventId: String): Cancelable { + override fun sendReaction(targetEventId: String, reaction: String): Cancelable { val event = eventFactory.createReactionEvent(roomId, targetEventId, reaction) - .also { - saveLocalEcho(it) - } + .also { saveLocalEcho(it) } val sendRelationWork = createSendEventWork(event, true) TimelineSendEventWorkCommon.postWork(context, roomId, sendRelationWork) return CancelableWork(context, sendRelationWork.id) } - override fun undoReaction(reaction: String, targetEventId: String, myUserId: String)/*: Cancelable*/ { - + override fun undoReaction(targetEventId: String, reaction: String): Cancelable { val params = FindReactionEventForUndoTask.Params( roomId, targetEventId, - reaction, - myUserId + reaction ) + // TODO We should avoid using MatrixCallback internally val callback = object : MatrixCallback { override fun onSuccess(data: FindReactionEventForUndoTask.Result) { if (data.redactEventId == null) { Timber.w("Cannot find reaction to undo (not yet synced?)") - //TODO? + // TODO? } data.redactEventId?.let { toRedact -> - - val redactEvent = eventFactory.createRedactEvent(roomId, toRedact, null).also { - saveLocalEcho(it) - } + val redactEvent = eventFactory.createRedactEvent(roomId, toRedact, null) + .also { saveLocalEcho(it) } val redactWork = createRedactEventWork(redactEvent, toRedact, null) TimelineSendEventWorkCommon.postWork(context, roomId, redactWork) - } } } - findReactionEventForUndoTask + return findReactionEventForUndoTask .configureWith(params) { this.retryCount = Int.MAX_VALUE this.callback = callback @@ -108,7 +101,7 @@ internal class DefaultRelationService @AssistedInject constructor(@Assisted priv .executeBy(taskExecutor) } - //TODO duplicate with send service? + // TODO duplicate with send service? private fun createRedactEventWork(localEvent: Event, eventId: String, reason: String?): OneTimeWorkRequest { val sendContentWorkerParams = RedactEventWorker.Params( userId, @@ -127,21 +120,17 @@ internal class DefaultRelationService @AssistedInject constructor(@Assisted priv compatibilityBodyText: String): Cancelable { val event = eventFactory .createReplaceTextEvent(roomId, targetEventId, newBodyText, newBodyAutoMarkdown, msgType, compatibilityBodyText) - .also { - saveLocalEcho(it) - } + .also { saveLocalEcho(it) } return if (cryptoService.isRoomEncrypted(roomId)) { val encryptWork = createEncryptEventWork(event, listOf("m.relates_to")) val workRequest = createSendEventWork(event, false) TimelineSendEventWorkCommon.postSequentialWorks(context, roomId, encryptWork, workRequest) CancelableWork(context, encryptWork.id) - } else { val workRequest = createSendEventWork(event, true) TimelineSendEventWorkCommon.postWork(context, roomId, workRequest) CancelableWork(context, workRequest.id) } - } override fun editReply(replyToEdit: TimelineEvent, @@ -153,15 +142,12 @@ internal class DefaultRelationService @AssistedInject constructor(@Assisted priv replyToEdit, originalTimelineEvent, newBodyText, true, MessageType.MSGTYPE_TEXT, compatibilityBodyText) - .also { - saveLocalEcho(it) - } + .also { saveLocalEcho(it) } return if (cryptoService.isRoomEncrypted(roomId)) { val encryptWork = createEncryptEventWork(event, listOf("m.relates_to")) val workRequest = createSendEventWork(event, false) TimelineSendEventWorkCommon.postSequentialWorks(context, roomId, encryptWork, workRequest) CancelableWork(context, encryptWork.id) - } else { val workRequest = createSendEventWork(event, true) TimelineSendEventWorkCommon.postWork(context, roomId, workRequest) @@ -179,22 +165,20 @@ internal class DefaultRelationService @AssistedInject constructor(@Assisted priv } override fun replyToMessage(eventReplied: TimelineEvent, replyText: String, autoMarkdown: Boolean): Cancelable? { - val event = eventFactory.createReplyTextEvent(roomId, eventReplied, replyText, autoMarkdown)?.also { - saveLocalEcho(it) - } ?: return null + val event = eventFactory.createReplyTextEvent(roomId, eventReplied, replyText, autoMarkdown) + ?.also { saveLocalEcho(it) } + ?: return null return if (cryptoService.isRoomEncrypted(roomId)) { val encryptWork = createEncryptEventWork(event, listOf("m.relates_to")) val workRequest = createSendEventWork(event, false) TimelineSendEventWorkCommon.postSequentialWorks(context, roomId, encryptWork, workRequest) CancelableWork(context, encryptWork.id) - } else { val workRequest = createSendEventWork(event, true) TimelineSendEventWorkCommon.postWork(context, roomId, workRequest) CancelableWork(context, workRequest.id) } - } private fun createEncryptEventWork(event: Event, keepKeys: List?): OneTimeWorkRequest { @@ -210,13 +194,13 @@ internal class DefaultRelationService @AssistedInject constructor(@Assisted priv return TimelineSendEventWorkCommon.createWork(sendWorkData, startChain) } - override fun getEventSummaryLive(eventId: String): LiveData { - val liveEntity = RealmLiveData(monarchy.realmConfiguration) { realm -> - EventAnnotationsSummaryEntity.where(realm, eventId) - } - return Transformations.map(liveEntity) { realmResults -> - realmResults.firstOrNull()?.asDomain() - ?: EventAnnotationsSummary(eventId, emptyList(), null) + override fun getEventSummaryLive(eventId: String): LiveData> { + val liveData = monarchy.findAllMappedWithChanges( + { EventAnnotationsSummaryEntity.where(it, eventId) }, + { it.asDomain() } + ) + return Transformations.map(liveData) { results -> + results.firstOrNull().toOptional() } } @@ -227,10 +211,6 @@ internal class DefaultRelationService @AssistedInject constructor(@Assisted priv * the same transaction id is received (in unsigned data) */ private fun saveLocalEcho(event: Event) { - monarchy.writeAsync { realm -> - val roomEntity = RoomEntity.where(realm, roomId = roomId).findFirst() - ?: return@writeAsync - roomEntity.addSendingEvent(event) - } + eventFactory.saveLocalEcho(monarchy, event) } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/relation/FetchEditHistoryTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/relation/FetchEditHistoryTask.kt index 792df3b1b6..5e5db58bdb 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/relation/FetchEditHistoryTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/relation/FetchEditHistoryTask.kt @@ -23,7 +23,6 @@ import im.vector.matrix.android.internal.session.room.RoomAPI import im.vector.matrix.android.internal.task.Task import javax.inject.Inject - internal interface FetchEditHistoryTask : Task> { data class Params( @@ -33,7 +32,6 @@ internal interface FetchEditHistoryTask : Task { data class Params( val roomId: String, val eventId: String, - val reaction: String, - val myUserId: String + val reaction: String ) data class Result( val redactEventId: String? ) - } -internal class DefaultFindReactionEventForUndoTask @Inject constructor(private val monarchy: Monarchy) : FindReactionEventForUndoTask { +internal class DefaultFindReactionEventForUndoTask @Inject constructor(private val monarchy: Monarchy, + @UserId private val userId: String) : FindReactionEventForUndoTask { override suspend fun execute(params: FindReactionEventForUndoTask.Params): FindReactionEventForUndoTask.Result { val eventId = Realm.getInstance(monarchy.realmConfiguration).use { realm -> - getReactionToRedact(realm, params.reaction, params.eventId, params.myUserId)?.eventId + getReactionToRedact(realm, params.reaction, params.eventId)?.eventId } return FindReactionEventForUndoTask.Result(eventId) } - private fun getReactionToRedact(realm: Realm, reaction: String, eventId: String, userId: String): EventEntity? { - val summary = EventAnnotationsSummaryEntity.where(realm, eventId).findFirst() - if (summary != null) { - summary.reactionsSummary.where() - .equalTo(ReactionAggregatedSummaryEntityFields.KEY, reaction) - .findFirst()?.let { - //want to find the event orignated by me! - it.sourceEvents.forEach { - //find source event - EventEntity.where(realm, it).findFirst()?.let { eventEntity -> - //is it mine? - if (eventEntity.sender == userId) { - return eventEntity - } - } - } - } - } - return null + private fun getReactionToRedact(realm: Realm, reaction: String, eventId: String): EventEntity? { + val summary = EventAnnotationsSummaryEntity.where(realm, eventId).findFirst() ?: return null + + val rase = summary.reactionsSummary.where() + .equalTo(ReactionAggregatedSummaryEntityFields.KEY, reaction) + .findFirst() ?: return null + + // want to find the event orignated by me! + return rase.sourceEvents + .asSequence() + .mapNotNull { + // find source event + EventEntity.where(realm, it).findFirst() + } + .firstOrNull { eventEntity -> + // is it mine? + eventEntity.sender == userId + } } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/relation/RelationsResponse.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/relation/RelationsResponse.kt index 737165ff0f..73e6592f7d 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/relation/RelationsResponse.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/relation/RelationsResponse.kt @@ -25,4 +25,4 @@ internal data class RelationsResponse( @Json(name = "original_event") val originalEvent: Event?, @Json(name = "next_batch") val nextBatch: String?, @Json(name = "prev_batch") val prevBatch: String? -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/relation/SendRelationWorker.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/relation/SendRelationWorker.kt index 5df995d9e9..eafe1e7419 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/relation/SendRelationWorker.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/relation/SendRelationWorker.kt @@ -73,8 +73,8 @@ internal class SendRelationWorker(context: Context, params: WorkerParameters) : when (exception) { is Failure.NetworkConnection -> Result.retry() else -> { - //TODO mark as failed to send? - //always return success, or the chain will be stuck for ever! + // TODO mark as failed to send? + // always return success, or the chain will be stuck for ever! Result.success() } } @@ -92,5 +92,4 @@ internal class SendRelationWorker(context: Context, params: WorkerParameters) : ) } } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/relation/UpdateQuickReactionTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/relation/UpdateQuickReactionTask.kt index fd081fbe55..6ec316e9a4 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/relation/UpdateQuickReactionTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/relation/UpdateQuickReactionTask.kt @@ -20,19 +20,18 @@ import im.vector.matrix.android.internal.database.model.EventAnnotationsSummaryE import im.vector.matrix.android.internal.database.model.EventEntity import im.vector.matrix.android.internal.database.model.ReactionAggregatedSummaryEntityFields import im.vector.matrix.android.internal.database.query.where +import im.vector.matrix.android.internal.di.UserId import im.vector.matrix.android.internal.task.Task import io.realm.Realm import javax.inject.Inject - internal interface UpdateQuickReactionTask : Task { data class Params( val roomId: String, val eventId: String, val reaction: String, - val oppositeReaction: String, - val myUserId: String + val oppositeReaction: String ) data class Result( @@ -41,23 +40,23 @@ internal interface UpdateQuickReactionTask : Task?>? = null monarchy.doWithRealm { realm -> - res = updateQuickReaction(realm, params.reaction, params.oppositeReaction, params.eventId, params.myUserId) + res = updateQuickReaction(realm, params.reaction, params.oppositeReaction, params.eventId) } return UpdateQuickReactionTask.Result(res?.first, res?.second ?: emptyList()) } - - private fun updateQuickReaction(realm: Realm, reaction: String, oppositeReaction: String, eventId: String, myUserId: String): Pair?> { - //the emoji reaction has been selected, we need to check if we have reacted it or not + private fun updateQuickReaction(realm: Realm, reaction: String, oppositeReaction: String, eventId: String): Pair?> { + // the emoji reaction has been selected, we need to check if we have reacted it or not val existingSummary = EventAnnotationsSummaryEntity.where(realm, eventId).findFirst() ?: return Pair(reaction, null) - //Ok there is already reactions on this event, have we reacted to it + // Ok there is already reactions on this event, have we reacted to it val aggregationForReaction = existingSummary.reactionsSummary.where() .equalTo(ReactionAggregatedSummaryEntityFields.KEY, reaction) .findFirst() @@ -66,23 +65,22 @@ internal class DefaultUpdateQuickReactionTask @Inject constructor(private val mo .findFirst() if (aggregationForReaction == null || !aggregationForReaction.addedByMe) { - //i haven't yet reacted to it, so need to add it, but do I need to redact the opposite? + // i haven't yet reacted to it, so need to add it, but do I need to redact the opposite? val toRedact = aggregationForOppositeReaction?.sourceEvents?.mapNotNull { - //find source event + // find source event val entity = EventEntity.where(realm, it).findFirst() - if (entity?.sender == myUserId) entity.eventId else null + if (entity?.sender == userId) entity.eventId else null } return Pair(reaction, toRedact) } else { - //I already added it, so i need to undo it (like a toggle) + // I already added it, so i need to undo it (like a toggle) // find all m.redaction coming from me to readact them val toRedact = aggregationForReaction.sourceEvents.mapNotNull { - //find source event + // find source event val entity = EventEntity.where(realm, it).findFirst() - if (entity?.sender == myUserId) entity.eventId else null + if (entity?.sender == userId) entity.eventId else null } return Pair(null, toRedact) } - } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/reporting/DefaultReportingService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/reporting/DefaultReportingService.kt new file mode 100644 index 0000000000..3b64cce439 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/reporting/DefaultReportingService.kt @@ -0,0 +1,46 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.matrix.android.internal.session.room.reporting + +import com.squareup.inject.assisted.Assisted +import com.squareup.inject.assisted.AssistedInject +import im.vector.matrix.android.api.MatrixCallback +import im.vector.matrix.android.api.session.room.reporting.ReportingService +import im.vector.matrix.android.api.util.Cancelable +import im.vector.matrix.android.internal.task.TaskExecutor +import im.vector.matrix.android.internal.task.configureWith + +internal class DefaultReportingService @AssistedInject constructor(@Assisted private val roomId: String, + private val taskExecutor: TaskExecutor, + private val reportContentTask: ReportContentTask +) : ReportingService { + + @AssistedInject.Factory + interface Factory { + fun create(roomId: String): ReportingService + } + + override fun reportContent(eventId: String, score: Int, reason: String, callback: MatrixCallback): Cancelable { + val params = ReportContentTask.Params(roomId, eventId, score, reason) + + return reportContentTask + .configureWith(params) { + this.callback = callback + } + .executeBy(taskExecutor) + } +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/reporting/ReportContentBody.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/reporting/ReportContentBody.kt new file mode 100644 index 0000000000..2cf33551ce --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/reporting/ReportContentBody.kt @@ -0,0 +1,33 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.matrix.android.internal.session.room.reporting + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +internal data class ReportContentBody( + /** + * Required. The score to rate this content as where -100 is most offensive and 0 is inoffensive. + */ + @Json(name = "score") val score: Int, + + /** + * Required. The reason the content is being reported. May be blank. + */ + @Json(name = "reason") val reason: String +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/reporting/ReportContentTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/reporting/ReportContentTask.kt new file mode 100644 index 0000000000..60c031158a --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/reporting/ReportContentTask.kt @@ -0,0 +1,39 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.matrix.android.internal.session.room.reporting + +import im.vector.matrix.android.internal.network.executeRequest +import im.vector.matrix.android.internal.session.room.RoomAPI +import im.vector.matrix.android.internal.task.Task +import javax.inject.Inject + +internal interface ReportContentTask : Task { + data class Params( + val roomId: String, + val eventId: String, + val score: Int, + val reason: String + ) +} + +internal class DefaultReportContentTask @Inject constructor(private val roomAPI: RoomAPI) : ReportContentTask { + override suspend fun execute(params: ReportContentTask.Params) { + return executeRequest { + apiCall = roomAPI.reportContent(params.roomId, params.eventId, ReportContentBody(params.score, params.reason)) + } + } +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/DefaultSendService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/DefaultSendService.kt index a342d3fe72..7c720e56a7 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/DefaultSendService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/DefaultSendService.kt @@ -106,7 +106,7 @@ internal class DefaultSendService @AssistedInject constructor(@Assisted private } override fun redactEvent(event: Event, reason: String?): Cancelable { - //TODO manage media/attachements? + // TODO manage media/attachements? val redactWork = createRedactEventWork(event, reason) TimelineSendEventWorkCommon.postWork(context, roomId, redactWork) return CancelableWork(context, redactWork.id) @@ -117,12 +117,11 @@ internal class DefaultSendService @AssistedInject constructor(@Assisted private return sendEvent(localEcho.root) } return null - } override fun resendMediaMessage(localEcho: TimelineEvent): Cancelable? { if (localEcho.root.isImageMessage() && localEcho.root.sendState.hasFailed()) { - //TODO this need a refactoring of attachement sending + // TODO this need a refactoring of attachement sending // val clearContent = localEcho.root.getClearContent() // val messageContent = clearContent?.toModel() ?: return null // when (messageContent.type) { @@ -158,7 +157,7 @@ internal class DefaultSendService @AssistedInject constructor(@Assisted private override fun deleteFailedEcho(localEcho: TimelineEvent) { monarchy.writeAsync { realm -> - TimelineEventEntity.where(realm, eventId = localEcho.root.eventId ?: "").findFirst()?.let { + TimelineEventEntity.where(realm, roomId = roomId, eventId = localEcho.root.eventId ?: "").findFirst()?.let { it.deleteFromRealm() } EventEntity.where(realm, eventId = localEcho.root.eventId ?: "").findFirst()?.let { @@ -176,7 +175,7 @@ internal class DefaultSendService @AssistedInject constructor(@Assisted private .build().let { TimelineSendEventWorkCommon.postWork(context, roomId, it, ExistingWorkPolicy.REPLACE) - //need to clear also image sending queue + // need to clear also image sending queue WorkManager.getInstance(context) .beginUniqueWork(buildWorkName(UPLOAD_WORK), ExistingWorkPolicy.REPLACE, it) .enqueue() @@ -189,7 +188,6 @@ internal class DefaultSendService @AssistedInject constructor(@Assisted private } } } - } override fun resendAllFailedMessages() { @@ -218,12 +216,11 @@ internal class DefaultSendService @AssistedInject constructor(@Assisted private MessageType.MSGTYPE_VIDEO, MessageType.MSGTYPE_IMAGE, MessageType.MSGTYPE_AUDIO -> { - //need to resend the attachement + // need to resend the attachement } else -> { Timber.e("Cannot resend message ${event.type} / ${content.type}") } - } } else { Timber.e("Unsupported message to resend ${event.type}") @@ -329,6 +326,4 @@ internal class DefaultSendService @AssistedInject constructor(@Assisted private .setBackoffCriteria(BackoffPolicy.LINEAR, BACKOFF_DELAY, TimeUnit.MILLISECONDS) .build() } - } - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/EncryptEventWorker.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/EncryptEventWorker.kt index 031ceb1681..a269529dd2 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/EncryptEventWorker.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/EncryptEventWorker.kt @@ -70,8 +70,7 @@ internal class EncryptEventWorker(context: Context, params: WorkerParameters) } localEchoUpdater.updateSendState(localEvent.eventId, SendState.ENCRYPTING) - - val localMutableContent = HashMap(localEvent.content) + val localMutableContent = localEvent.content?.toMutableMap() ?: mutableMapOf() params.keepKeys?.forEach { localMutableContent.remove(it) } @@ -89,7 +88,7 @@ internal class EncryptEventWorker(context: Context, params: WorkerParameters) val modifiedContent = HashMap(result.eventContent) params.keepKeys?.forEach { toKeep -> localEvent.content?.get(toKeep)?.let { - //put it back in the encrypted thing + // put it back in the encrypted thing modifiedContent[toKeep] = it } } @@ -106,7 +105,7 @@ internal class EncryptEventWorker(context: Context, params: WorkerParameters) else -> SendState.UNDELIVERED } localEchoUpdater.updateSendState(localEvent.eventId, sendState) - //always return success, or the chain will be stuck for ever! + // always return success, or the chain will be stuck for ever! val nextWorkerParams = SendEventWorker.Params(params.userId, params.roomId, localEvent, error?.localizedMessage ?: "Error") return Result.success(WorkerParamsFactory.toData(nextWorkerParams)) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/LocalEchoEventFactory.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/LocalEchoEventFactory.kt index ffc539471b..49c813ece6 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/LocalEchoEventFactory.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/LocalEchoEventFactory.kt @@ -17,6 +17,7 @@ package im.vector.matrix.android.internal.session.room.send import android.media.MediaMetadataRetriever +import androidx.exifinterface.media.ExifInterface import com.zhuinden.monarchy.Monarchy import im.vector.matrix.android.R import im.vector.matrix.android.api.permalinks.PermalinkFactory @@ -159,7 +160,7 @@ internal class LocalEchoEventFactory @Inject constructor(@UserId private val use reaction ) ) - val localId = dummyEventId(roomId) + val localId = LocalEcho.createLocalEchoId() return Event( roomId = roomId, originServerTs = dummyOriginServerTs(), @@ -168,18 +169,30 @@ internal class LocalEchoEventFactory @Inject constructor(@UserId private val use type = EventType.REACTION, content = content.toContent(), unsignedData = UnsignedData(age = null, transactionId = localId)) - } - private fun createImageEvent(roomId: String, attachment: ContentAttachmentData): Event { + var width = attachment.width + var height = attachment.height + + when (attachment.exifOrientation) { + ExifInterface.ORIENTATION_ROTATE_90, + ExifInterface.ORIENTATION_TRANSVERSE, + ExifInterface.ORIENTATION_ROTATE_270, + ExifInterface.ORIENTATION_TRANSPOSE -> { + val tmp = width + width = height + height = tmp + } + } + val content = MessageImageContent( type = MessageType.MSGTYPE_IMAGE, body = attachment.name ?: "image", info = ImageInfo( mimeType = attachment.mimeType, - width = attachment.width?.toInt() ?: 0, - height = attachment.height?.toInt() ?: 0, + width = width?.toInt() ?: 0, + height = height?.toInt() ?: 0, size = attachment.size.toInt() ), url = attachment.path @@ -251,7 +264,7 @@ internal class LocalEchoEventFactory @Inject constructor(@UserId private val use } private fun createEvent(roomId: String, content: Any? = null): Event { - val localID = dummyEventId(roomId) + val localID = LocalEcho.createLocalEchoId() return Event( roomId = roomId, originServerTs = dummyOriginServerTs(), @@ -267,13 +280,9 @@ internal class LocalEchoEventFactory @Inject constructor(@UserId private val use return System.currentTimeMillis() } - private fun dummyEventId(roomId: String): String { - return "$LOCAL_ID_PREFIX${UUID.randomUUID()}" - } - fun createReplyTextEvent(roomId: String, eventReplied: TimelineEvent, replyText: String, autoMarkdown: Boolean): Event? { - //Fallbacks and event representation - //TODO Add error/warning logs when any of this is null + // Fallbacks and event representation + // TODO Add error/warning logs when any of this is null val permalink = PermalinkFactory.createPermalink(eventReplied.root) ?: return null val userId = eventReplied.root.senderId ?: return null val userLink = PermalinkFactory.createPermalink(userId) ?: return null @@ -339,10 +348,11 @@ internal class LocalEchoEventFactory @Inject constructor(@UserId private val use } } val isReply = content.isReply() || originalContent.isReply() - return if (isReply) + return if (isReply) { TextContent(content.body, formattedText).removeInReplyFallbacks() - else + } else { TextContent(content.body, formattedText) + } } MessageType.MSGTYPE_FILE -> return TextContent(stringProvider.getString(R.string.reply_to_a_file)) MessageType.MSGTYPE_AUDIO -> return TextContent(stringProvider.getString(R.string.reply_to_an_audio_file)) @@ -369,7 +379,7 @@ internal class LocalEchoEventFactory @Inject constructor(@UserId private val use } */ fun createRedactEvent(roomId: String, eventId: String, reason: String?): Event { - val localID = dummyEventId(roomId) + val localID = LocalEcho.createLocalEchoId() return Event( roomId = roomId, originServerTs = dummyOriginServerTs(), @@ -383,7 +393,7 @@ internal class LocalEchoEventFactory @Inject constructor(@UserId private val use } fun saveLocalEcho(monarchy: Monarchy, event: Event) { - if (event.roomId == null) throw IllegalStateException("Your event should have a roomId") + checkNotNull(event.roomId) { "Your event should have a roomId" } monarchy.writeAsync { realm -> val roomEntity = RoomEntity.where(realm, roomId = event.roomId).findFirst() ?: return@writeAsync @@ -393,9 +403,6 @@ internal class LocalEchoEventFactory @Inject constructor(@UserId private val use } companion object { - const val LOCAL_ID_PREFIX = "local." - - // //
// In reply to @@ -406,7 +413,5 @@ internal class LocalEchoEventFactory @Inject constructor(@UserId private val use // // No whitespace because currently breaks temporary formatted text to Span const val REPLY_PATTERN = """
%s%s
%s
%s""" - - fun isLocalEchoId(eventId: String): Boolean = eventId.startsWith(LOCAL_ID_PREFIX) } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/LocalEchoUpdater.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/LocalEchoUpdater.kt index c4242239ee..4c45ba0a4d 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/LocalEchoUpdater.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/LocalEchoUpdater.kt @@ -32,12 +32,11 @@ internal class LocalEchoUpdater @Inject constructor(private val monarchy: Monarc val sendingEventEntity = EventEntity.where(realm, eventId).findFirst() if (sendingEventEntity != null) { if (sendState == SendState.SENT && sendingEventEntity.sendState == SendState.SYNCED) { - //If already synced, do not put as sent + // If already synced, do not put as sent } else { sendingEventEntity.sendState = sendState } } } } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/NoMerger.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/NoMerger.kt index c41c4bc04d..05b31ca420 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/NoMerger.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/NoMerger.kt @@ -25,4 +25,4 @@ internal class NoMerger : InputMerger() { override fun merge(inputs: MutableList): Data { return inputs.first() } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/RedactEventWorker.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/RedactEventWorker.kt index bac71cf7bd..ec311458cd 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/RedactEventWorker.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/RedactEventWorker.kt @@ -71,8 +71,8 @@ internal class RedactEventWorker(context: Context, params: WorkerParameters) : C when (it) { is Failure.NetworkConnection -> Result.retry() else -> { - //TODO mark as failed to send? - //always return success, or the chain will be stuck for ever! + // TODO mark as failed to send? + // always return success, or the chain will be stuck for ever! Result.success(WorkerParamsFactory.toData(params.copy( lastFailureMessage = it.localizedMessage ))) @@ -81,5 +81,4 @@ internal class RedactEventWorker(context: Context, params: WorkerParameters) : C } ) } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/SendEventWorker.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/SendEventWorker.kt index 442c60842f..183b0ad9b8 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/SendEventWorker.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/SendEventWorker.kt @@ -32,7 +32,6 @@ import im.vector.matrix.android.internal.worker.WorkerParamsFactory import im.vector.matrix.android.internal.worker.getSessionComponent import javax.inject.Inject - internal class SendEventWorker constructor(context: Context, params: WorkerParameters) : CoroutineWorker(context, params) { @@ -72,7 +71,7 @@ internal class SendEventWorker constructor(context: Context, params: WorkerParam Result.retry() } else { localEchoUpdater.updateSendState(event.eventId, SendState.UNDELIVERED) - //always return success, or the chain will be stuck for ever! + // always return success, or the chain will be stuck for ever! Result.success() } } @@ -95,5 +94,4 @@ internal class SendEventWorker constructor(context: Context, params: WorkerParam } localEchoUpdater.updateSendState(eventId, SendState.SENT) } - } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/SendResponse.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/SendResponse.kt index d11c5164ee..947edee1ed 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/SendResponse.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/SendResponse.kt @@ -22,4 +22,4 @@ import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) internal data class SendResponse( @Json(name = "event_id") val eventId: String -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/TextContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/TextContent.kt index bf7cb36188..27b68e95eb 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/TextContent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/TextContent.kt @@ -26,13 +26,11 @@ import im.vector.matrix.android.api.util.ContentUtils.extractUsefulTextFromReply */ data class TextContent( val text: String, - val formattedText: String? = null ) { fun takeFormatted() = formattedText ?: text } - fun TextContent.toMessageTextContent(msgType: String = MessageType.MSGTYPE_TEXT): MessageTextContent { return MessageTextContent( type = msgType, @@ -48,5 +46,3 @@ fun TextContent.removeInReplyFallbacks(): TextContent { formattedText = this.formattedText?.let { extractUsefulTextFromHtmlReply(it) } ) } - - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/state/DefaultStateService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/state/DefaultStateService.kt index f51b0e0448..785fd9ae71 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/state/DefaultStateService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/state/DefaultStateService.kt @@ -57,13 +57,10 @@ internal class DefaultStateService @AssistedInject constructor(@Assisted private "topic" to topic )) - sendStateTask .configureWith(params) { this.callback = callback } .executeBy(taskExecutor) } - - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/ClearUnlinkedEventsTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/ClearUnlinkedEventsTask.kt new file mode 100644 index 0000000000..04cf810fe4 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/ClearUnlinkedEventsTask.kt @@ -0,0 +1,48 @@ +/* + + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + + */ +package im.vector.matrix.android.internal.session.room.timeline + +import com.zhuinden.monarchy.Monarchy +import im.vector.matrix.android.internal.database.helper.deleteOnCascade +import im.vector.matrix.android.internal.database.model.ChunkEntity +import im.vector.matrix.android.internal.database.model.ChunkEntityFields +import im.vector.matrix.android.internal.database.model.EventEntityFields +import im.vector.matrix.android.internal.database.query.where +import im.vector.matrix.android.internal.task.Task +import im.vector.matrix.android.internal.util.awaitTransaction +import javax.inject.Inject + +internal interface ClearUnlinkedEventsTask : Task { + + data class Params(val roomId: String) +} + +internal class DefaultClearUnlinkedEventsTask @Inject constructor(private val monarchy: Monarchy) : ClearUnlinkedEventsTask { + + override suspend fun execute(params: ClearUnlinkedEventsTask.Params) { + monarchy.awaitTransaction { localRealm -> + val unlinkedChunks = ChunkEntity + .where(localRealm, roomId = params.roomId) + .equalTo("${ChunkEntityFields.TIMELINE_EVENTS.ROOT}.${EventEntityFields.IS_UNLINKED}", true) + .findAll() + unlinkedChunks.forEach { + it.deleteOnCascade() + } + } + } +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/DefaultGetContextOfEventTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/DefaultGetContextOfEventTask.kt index efd099e9f9..96e1caf71b 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/DefaultGetContextOfEventTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/DefaultGetContextOfEventTask.kt @@ -28,7 +28,6 @@ internal interface GetContextOfEventTask : Task { data class Params( @@ -31,7 +30,6 @@ internal interface PaginationTask : Task + private lateinit var nonFilteredEvents: RealmResults + private lateinit var filteredEvents: RealmResults private lateinit var eventRelations: RealmResults private var roomEntity: RoomEntity? = null - private var prevDisplayIndex: Int = DISPLAY_INDEX_UNKNOWN - private var nextDisplayIndex: Int = DISPLAY_INDEX_UNKNOWN - private val isLive = initialEventId == null + private var prevDisplayIndex: Int? = null + private var nextDisplayIndex: Int? = null private val builtEvents = Collections.synchronizedList(ArrayList()) private val builtEventsIdMap = Collections.synchronizedMap(HashMap()) - private val backwardsPaginationState = AtomicReference(PaginationState()) - private val forwardsPaginationState = AtomicReference(PaginationState()) + private val backwardsState = AtomicReference(State()) + private val forwardsState = AtomicReference(State()) private val timelineID = UUID.randomUUID().toString() + override val isLive + get() = !hasMoreToLoad(Timeline.Direction.FORWARDS) + private val eventDecryptor = TimelineEventDecryptor(realmConfiguration, timelineID, cryptoService) private val eventsChangeListener = OrderedRealmCollectionChangeListener> { results, changeSet -> + if (!results.isLoaded || !results.isValid) { + return@OrderedRealmCollectionChangeListener + } if (changeSet.state == OrderedCollectionChangeSet.State.INITIAL) { handleInitialLoad() } else { - // If changeSet has deletion we are having a gap, so we clear everything - if (changeSet.deletionRanges.isNotEmpty()) { - prevDisplayIndex = DISPLAY_INDEX_UNKNOWN - nextDisplayIndex = DISPLAY_INDEX_UNKNOWN - builtEvents.clear() - builtEventsIdMap.clear() - } - changeSet.insertionRanges.forEach { range -> - val (startDisplayIndex, direction) = if (range.startIndex == 0) { - Pair(liveEvents[range.length - 1]!!.root!!.displayIndex, Timeline.Direction.FORWARDS) - } else { - Pair(liveEvents[range.startIndex]!!.root!!.displayIndex, Timeline.Direction.BACKWARDS) - } - val state = getPaginationState(direction) - if (state.isPaginating) { - // We are getting new items from pagination - val shouldPostSnapshot = paginateInternal(startDisplayIndex, direction, state.requestedCount) - if (shouldPostSnapshot) { - postSnapshot() - } - } else { - // We are getting new items from sync - buildTimelineEvents(startDisplayIndex, direction, range.length.toLong()) - postSnapshot() - } - } - - var hasChanged = false - changeSet.changes.forEach { index -> - val eventEntity = results[index] - eventEntity?.eventId?.let { eventId -> - builtEventsIdMap[eventId]?.let { builtIndex -> - //Update an existing event - builtEvents[builtIndex]?.let { te -> - builtEvents[builtIndex] = buildTimelineEvent(eventEntity) - hasChanged = true - } - } - } - } - if (hasChanged) postSnapshot() + handleUpdates(changeSet) } } private val relationsListener = OrderedRealmCollectionChangeListener> { collection, changeSet -> - var hasChange = false (changeSet.insertions + changeSet.changes).forEach { val eventRelations = collection[it] if (eventRelations != null) { - builtEventsIdMap[eventRelations.eventId]?.let { builtIndex -> - //Update the relation of existing event - builtEvents[builtIndex]?.let { te -> - builtEvents[builtIndex] = te.copy(annotations = eventRelations.asDomain()) - hasChange = true - } - } + hasChange = rebuildEvent(eventRelations.eventId) { te -> + te.copy(annotations = eventRelations.asDomain()) + } || hasChange } } - if (hasChange) - postSnapshot() + if (hasChange) postSnapshot() } - - // Public methods ****************************************************************************** +// Public methods ****************************************************************************** override fun paginate(direction: Timeline.Direction, count: Int) { BACKGROUND_HANDLER.post { @@ -214,12 +172,10 @@ internal class DefaultTimeline( override fun start() { if (isStarted.compareAndSet(false, true)) { Timber.v("Start timeline for roomId: $roomId and eventId: $initialEventId") - eventDecryptor.start() BACKGROUND_HANDLER.post { + eventDecryptor.start() val realm = Realm.getInstance(realmConfiguration) backgroundRealm.set(realm) - clearUnlinkedEvents(realm) - roomEntity = RoomEntity.where(realm, roomId = roomId).findFirst()?.also { it.sendingTimelineEvents.addChangeListener { _ -> @@ -227,9 +183,9 @@ internal class DefaultTimeline( } } - liveEvents = buildEventQuery(realm) + nonFilteredEvents = buildEventQuery(realm).sort(TimelineEventEntityFields.ROOT.DISPLAY_INDEX, Sort.DESCENDING).findAll() + filteredEvents = nonFilteredEvents.where() .filterEventsWithSettings() - .sort(TimelineEventEntityFields.ROOT.DISPLAY_INDEX, Sort.DESCENDING) .findAllAsync() .also { it.addChangeListener(eventsChangeListener) } @@ -238,9 +194,9 @@ internal class DefaultTimeline( .also { it.addChangeListener(relationsListener) } if (settings.buildReadReceipts) { - hiddenReadReceipts.start(realm, liveEvents, this) + hiddenReadReceipts.start(realm, filteredEvents, nonFilteredEvents, this) } - + hiddenReadMarker.start(realm, filteredEvents, nonFilteredEvents, this) isReady.set(true) } } @@ -248,19 +204,91 @@ internal class DefaultTimeline( override fun dispose() { if (isStarted.compareAndSet(true, false)) { - eventDecryptor.destroy() + isReady.set(false) Timber.v("Dispose timeline for roomId: $roomId and eventId: $initialEventId") + cancelableBag.cancel() + BACKGROUND_HANDLER.removeCallbacksAndMessages(null) BACKGROUND_HANDLER.post { - cancelableBag.cancel() roomEntity?.sendingTimelineEvents?.removeAllChangeListeners() - eventRelations.removeAllChangeListeners() - liveEvents.removeAllChangeListeners() + if (this::eventRelations.isInitialized) { + eventRelations.removeAllChangeListeners() + } + if (this::filteredEvents.isInitialized) { + filteredEvents.removeAllChangeListeners() + } + hiddenReadMarker.dispose() if (settings.buildReadReceipts) { hiddenReadReceipts.dispose() } + clearAllValues() backgroundRealm.getAndSet(null).also { - it.close() + it?.close() } + eventDecryptor.destroy() + } + clearUnlinkedEventsTask + .configureWith(ClearUnlinkedEventsTask.Params(roomId)) + .executeBy(taskExecutor) + } + } + + override fun restartWithEventId(eventId: String?) { + dispose() + initialEventId = eventId + start() + postSnapshot() + } + + override fun getTimelineEventAtIndex(index: Int): TimelineEvent? { + return builtEvents.getOrNull(index) + } + + override fun getIndexOfEvent(eventId: String?): Int? { + return builtEventsIdMap[eventId] + } + + override fun getTimelineEventWithId(eventId: String?): TimelineEvent? { + return builtEventsIdMap[eventId]?.let { + getTimelineEventAtIndex(it) + } + } + + override fun getFirstDisplayableEventId(eventId: String): String? { + // If the item is built, the id is obviously displayable + val builtIndex = builtEventsIdMap[eventId] + if (builtIndex != null) { + return eventId + } + // Otherwise, we should check if the event is in the db, but is hidden because of filters + return Realm.getInstance(realmConfiguration).use { localRealm -> + val nonFilteredEvents = buildEventQuery(localRealm) + .sort(TimelineEventEntityFields.ROOT.DISPLAY_INDEX, Sort.DESCENDING) + .findAll() + + val nonFilteredEvent = nonFilteredEvents.where() + .equalTo(TimelineEventEntityFields.EVENT_ID, eventId) + .findFirst() + + val filteredEvents = nonFilteredEvents.where().filterEventsWithSettings().findAll() + val isEventInDb = nonFilteredEvent != null + + val isHidden = isEventInDb && filteredEvents.where() + .equalTo(TimelineEventEntityFields.EVENT_ID, eventId) + .findFirst() == null + + if (isHidden) { + val displayIndex = nonFilteredEvent?.root?.displayIndex + if (displayIndex != null) { + // Then we are looking for the first displayable event after the hidden one + val firstDisplayedEvent = filteredEvents.where() + .lessThanOrEqualTo(TimelineEventEntityFields.ROOT.DISPLAY_INDEX, displayIndex) + .findFirst() + firstDisplayedEvent?.eventId + } else { + null + } + } else { + null } } } @@ -269,71 +297,86 @@ internal class DefaultTimeline( return hasMoreInCache(direction) || !hasReachedEnd(direction) } - // TimelineHiddenReadReceipts.Delegate +// TimelineHiddenReadReceipts.Delegate override fun rebuildEvent(eventId: String, readReceipts: List): Boolean { - return builtEventsIdMap[eventId]?.let { builtIndex -> - //Update the relation of existing event - builtEvents[builtIndex]?.let { te -> - builtEvents[builtIndex] = te.copy(readReceipts = readReceipts) - true - } - } ?: false + return rebuildEvent(eventId) { te -> + te.copy(readReceipts = readReceipts) + } } override fun onReadReceiptsUpdated() { postSnapshot() } +// TimelineHiddenReadMarker.Delegate + + override fun rebuildEvent(eventId: String, hasReadMarker: Boolean): Boolean { + return rebuildEvent(eventId) { te -> + te.copy(hasReadMarker = hasReadMarker) + } + } + + override fun onReadMarkerUpdated() { + postSnapshot() + } + // Private methods ***************************************************************************** - private fun hasMoreInCache(direction: Timeline.Direction): Boolean { - return Realm.getInstance(realmConfiguration).use { localRealm -> - val timelineEventEntity = buildEventQuery(localRealm).findFirst(direction) - ?: return false - if (direction == Timeline.Direction.FORWARDS) { - if (findCurrentChunk(localRealm)?.isLastForward == true) { - return false - } - val firstEvent = builtEvents.firstOrNull() ?: return true - firstEvent.displayIndex < timelineEventEntity.root!!.displayIndex - } else { - val lastEvent = builtEvents.lastOrNull() ?: return true - lastEvent.displayIndex > timelineEventEntity.root!!.displayIndex + private fun rebuildEvent(eventId: String, builder: (TimelineEvent) -> TimelineEvent): Boolean { + return builtEventsIdMap[eventId]?.let { builtIndex -> + // Update the relation of existing event + builtEvents[builtIndex]?.let { te -> + builtEvents[builtIndex] = builder(te) + true } - } + } ?: false } - private fun hasReachedEnd(direction: Timeline.Direction): Boolean { - return Realm.getInstance(realmConfiguration).use { localRealm -> - val currentChunk = findCurrentChunk(localRealm) ?: return false - if (direction == Timeline.Direction.FORWARDS) { - currentChunk.isLastForward - } else { - val eventEntity = buildEventQuery(localRealm).findFirst(direction) - currentChunk.isLastBackward || eventEntity?.root?.type == EventType.STATE_ROOM_CREATE - } + private fun hasMoreInCache(direction: Timeline.Direction) = getState(direction).hasMoreInCache + + private fun hasReachedEnd(direction: Timeline.Direction) = getState(direction).hasReachedEnd + + private fun updateLoadingStates(results: RealmResults) { + val lastCacheEvent = results.lastOrNull() + val lastBuiltEvent = builtEvents.lastOrNull() + val firstCacheEvent = results.firstOrNull() + val firstBuiltEvent = builtEvents.firstOrNull() + val chunkEntity = getLiveChunk() + + updateState(Timeline.Direction.FORWARDS) { + it.copy( + hasMoreInCache = firstBuiltEvent == null || firstBuiltEvent.displayIndex < firstCacheEvent?.root?.displayIndex ?: Int.MIN_VALUE, + hasReachedEnd = chunkEntity?.isLastForward ?: false + ) + } + + updateState(Timeline.Direction.BACKWARDS) { + it.copy( + hasMoreInCache = lastBuiltEvent == null || lastBuiltEvent.displayIndex > lastCacheEvent?.root?.displayIndex ?: Int.MAX_VALUE, + hasReachedEnd = chunkEntity?.isLastBackward ?: false || lastCacheEvent?.root?.type == EventType.STATE_ROOM_CREATE + ) } } - /** * This has to be called on TimelineThread as it access realm live results * @return true if createSnapshot should be posted */ - private fun paginateInternal(startDisplayIndex: Int, + private fun paginateInternal(startDisplayIndex: Int?, direction: Timeline.Direction, - count: Int): Boolean { - updatePaginationState(direction) { it.copy(requestedCount = count, isPaginating = true) } - val builtCount = buildTimelineEvents(startDisplayIndex, direction, count.toLong()) + count: Int, + strict: Boolean = false): Boolean { + updateState(direction) { it.copy(requestedPaginationCount = count, isPaginating = true) } + val builtCount = buildTimelineEvents(startDisplayIndex, direction, count.toLong(), strict) val shouldFetchMore = builtCount < count && !hasReachedEnd(direction) if (shouldFetchMore) { val newRequestedCount = count - builtCount - updatePaginationState(direction) { it.copy(requestedCount = newRequestedCount) } - val fetchingCount = Math.max(MIN_FETCHING_COUNT, newRequestedCount) + updateState(direction) { it.copy(requestedPaginationCount = newRequestedCount) } + val fetchingCount = max(MIN_FETCHING_COUNT, newRequestedCount) executePaginationTask(direction, fetchingCount) } else { - updatePaginationState(direction) { it.copy(isPaginating = false, requestedCount = 0) } + updateState(direction) { it.copy(isPaginating = false, requestedPaginationCount = 0) } } return !shouldFetchMore @@ -345,7 +388,7 @@ internal class DefaultTimeline( private fun buildSendingEvents(): List { val sendingEvents = ArrayList() - if (hasReachedEnd(Timeline.Direction.FORWARDS)) { + if (hasReachedEnd(Timeline.Direction.FORWARDS) && !hasMoreInCache(Timeline.Direction.FORWARDS)) { roomEntity?.sendingTimelineEvents ?.where() ?.filterEventsWithSettings() @@ -358,20 +401,20 @@ internal class DefaultTimeline( } private fun canPaginate(direction: Timeline.Direction): Boolean { - return isReady.get() && !getPaginationState(direction).isPaginating && hasMoreToLoad(direction) + return isReady.get() && !getState(direction).isPaginating && hasMoreToLoad(direction) } - private fun getPaginationState(direction: Timeline.Direction): PaginationState { + private fun getState(direction: Timeline.Direction): State { return when (direction) { - Timeline.Direction.FORWARDS -> forwardsPaginationState.get() - Timeline.Direction.BACKWARDS -> backwardsPaginationState.get() + Timeline.Direction.FORWARDS -> forwardsState.get() + Timeline.Direction.BACKWARDS -> backwardsState.get() } } - private fun updatePaginationState(direction: Timeline.Direction, update: (PaginationState) -> PaginationState) { + private fun updateState(direction: Timeline.Direction, update: (State) -> State) { val stateReference = when (direction) { - Timeline.Direction.FORWARDS -> forwardsPaginationState - Timeline.Direction.BACKWARDS -> backwardsPaginationState + Timeline.Direction.FORWARDS -> forwardsState + Timeline.Direction.BACKWARDS -> backwardsState } val currentValue = stateReference.get() val newValue = update(currentValue) @@ -383,41 +426,84 @@ internal class DefaultTimeline( */ private fun handleInitialLoad() { var shouldFetchInitialEvent = false - val initialDisplayIndex = if (isLive) { - liveEvents.firstOrNull()?.root?.displayIndex + val currentInitialEventId = initialEventId + val initialDisplayIndex = if (currentInitialEventId == null) { + filteredEvents.firstOrNull()?.root?.displayIndex } else { - val initialEvent = liveEvents.where() + val initialEvent = nonFilteredEvents.where() .equalTo(TimelineEventEntityFields.EVENT_ID, initialEventId) .findFirst() + shouldFetchInitialEvent = initialEvent == null initialEvent?.root?.displayIndex - } ?: DISPLAY_INDEX_UNKNOWN - + } prevDisplayIndex = initialDisplayIndex nextDisplayIndex = initialDisplayIndex - if (initialEventId != null && shouldFetchInitialEvent) { - fetchEvent(initialEventId) + if (currentInitialEventId != null && shouldFetchInitialEvent) { + fetchEvent(currentInitialEventId) } else { - val count = Math.min(settings.initialSize, liveEvents.size) - if (isLive) { - paginateInternal(initialDisplayIndex, Timeline.Direction.BACKWARDS, count) + val count = min(settings.initialSize, filteredEvents.size) + if (initialEventId == null) { + paginateInternal(initialDisplayIndex, Timeline.Direction.BACKWARDS, count, strict = false) } else { - paginateInternal(initialDisplayIndex, Timeline.Direction.FORWARDS, count / 2) - paginateInternal(initialDisplayIndex, Timeline.Direction.BACKWARDS, count / 2) + paginateInternal(initialDisplayIndex, Timeline.Direction.FORWARDS, count / 2, strict = false) + paginateInternal(initialDisplayIndex, Timeline.Direction.BACKWARDS, count / 2, strict = true) } } postSnapshot() } + /** + * This has to be called on TimelineThread as it access realm live results + */ + private fun handleUpdates(changeSet: OrderedCollectionChangeSet) { + // If changeSet has deletion we are having a gap, so we clear everything + if (changeSet.deletionRanges.isNotEmpty()) { + clearAllValues() + } + var postSnapshot = false + changeSet.insertionRanges.forEach { range -> + val (startDisplayIndex, direction) = if (range.startIndex == 0) { + Pair(filteredEvents[range.length - 1]!!.root!!.displayIndex, Timeline.Direction.FORWARDS) + } else { + Pair(filteredEvents[range.startIndex]!!.root!!.displayIndex, Timeline.Direction.BACKWARDS) + } + val state = getState(direction) + if (state.isPaginating) { + // We are getting new items from pagination + postSnapshot = paginateInternal(startDisplayIndex, direction, state.requestedPaginationCount) + } else { + // We are getting new items from sync + buildTimelineEvents(startDisplayIndex, direction, range.length.toLong()) + postSnapshot = true + } + } + changeSet.changes.forEach { index -> + val eventEntity = filteredEvents[index] + eventEntity?.eventId?.let { eventId -> + postSnapshot = rebuildEvent(eventId) { + buildTimelineEvent(eventEntity) + } || postSnapshot + } + } + if (postSnapshot) { + postSnapshot() + } + } + /** * This has to be called on TimelineThread as it access realm live results */ private fun executePaginationTask(direction: Timeline.Direction, limit: Int) { - val token = getTokenLive(direction) ?: return + val token = getTokenLive(direction) + if (token == null) { + updateState(direction) { it.copy(isPaginating = false, requestedPaginationCount = 0) } + return + } val params = PaginationTask.Params(roomId = roomId, - from = token, - direction = direction.toPaginationDirection(), - limit = limit) + from = token, + direction = direction.toPaginationDirection(), + limit = limit) Timber.v("Should fetch $limit items $direction") cancelableBag += paginationTask @@ -426,13 +512,18 @@ internal class DefaultTimeline( this.constraints = TaskConstraints(connectedToNetwork = true) this.callback = object : MatrixCallback { override fun onSuccess(data: TokenChunkEventPersistor.Result) { - if (data == TokenChunkEventPersistor.Result.SUCCESS) { - Timber.v("Success fetching $limit items $direction from pagination request") - } else { - // Database won't be updated, so we force pagination request - BACKGROUND_HANDLER.post { - executePaginationTask(direction, limit) + when (data) { + TokenChunkEventPersistor.Result.SUCCESS -> { + Timber.v("Success fetching $limit items $direction from pagination request") } + TokenChunkEventPersistor.Result.REACHED_END -> { + postSnapshot() + } + TokenChunkEventPersistor.Result.SHOULD_FETCH_MORE -> + // Database won't be updated, so we force pagination request + BACKGROUND_HANDLER.post { + executePaginationTask(direction, limit) + } } } @@ -453,26 +544,26 @@ internal class DefaultTimeline( return if (direction == Timeline.Direction.BACKWARDS) chunkEntity.prevToken else chunkEntity.nextToken } - /** * This has to be called on TimelineThread as it access realm live results */ private fun getLiveChunk(): ChunkEntity? { - return liveEvents.firstOrNull()?.chunk?.firstOrNull() + return filteredEvents.firstOrNull()?.chunk?.firstOrNull() } /** * This has to be called on TimelineThread as it access realm live results * @return number of items who have been added */ - private fun buildTimelineEvents(startDisplayIndex: Int, + private fun buildTimelineEvents(startDisplayIndex: Int?, direction: Timeline.Direction, - count: Long): Int { - if (count < 1) { + count: Long, + strict: Boolean = false): Int { + if (count < 1 || startDisplayIndex == null) { return 0 } val start = System.currentTimeMillis() - val offsetResults = getOffsetResults(startDisplayIndex, direction, count) + val offsetResults = getOffsetResults(startDisplayIndex, direction, count, strict) if (offsetResults.isEmpty()) { return 0 } @@ -487,13 +578,13 @@ internal class DefaultTimeline( val timelineEvent = buildTimelineEvent(eventEntity) if (timelineEvent.isEncrypted() - && timelineEvent.root.mxDecryptionResult == null) { + && timelineEvent.root.mxDecryptionResult == null) { timelineEvent.root.eventId?.let { eventDecryptor.requestDecryption(it) } } val position = if (direction == Timeline.Direction.FORWARDS) 0 else builtEvents.size builtEvents.add(position, timelineEvent) - //Need to shift :/ + // Need to shift :/ builtEventsIdMap.entries.filter { it.value >= position }.forEach { it.setValue(it.value + 1) } builtEventsIdMap[eventEntity.eventId] = position } @@ -513,23 +604,29 @@ internal class DefaultTimeline( */ private fun getOffsetResults(startDisplayIndex: Int, direction: Timeline.Direction, - count: Long): RealmResults { - val offsetQuery = liveEvents.where() + count: Long, + strict: Boolean): RealmResults { + val offsetQuery = filteredEvents.where() if (direction == Timeline.Direction.BACKWARDS) { - offsetQuery - .sort(TimelineEventEntityFields.ROOT.DISPLAY_INDEX, Sort.DESCENDING) - .lessThanOrEqualTo(TimelineEventEntityFields.ROOT.DISPLAY_INDEX, startDisplayIndex) + offsetQuery.sort(TimelineEventEntityFields.ROOT.DISPLAY_INDEX, Sort.DESCENDING) + if (strict) { + offsetQuery.lessThan(TimelineEventEntityFields.ROOT.DISPLAY_INDEX, startDisplayIndex) + } else { + offsetQuery.lessThanOrEqualTo(TimelineEventEntityFields.ROOT.DISPLAY_INDEX, startDisplayIndex) + } } else { - offsetQuery - .sort(TimelineEventEntityFields.ROOT.DISPLAY_INDEX, Sort.ASCENDING) - .greaterThanOrEqualTo(TimelineEventEntityFields.ROOT.DISPLAY_INDEX, startDisplayIndex) + offsetQuery.sort(TimelineEventEntityFields.ROOT.DISPLAY_INDEX, Sort.ASCENDING) + if (strict) { + offsetQuery.greaterThan(TimelineEventEntityFields.ROOT.DISPLAY_INDEX, startDisplayIndex) + } else { + offsetQuery.greaterThanOrEqualTo(TimelineEventEntityFields.ROOT.DISPLAY_INDEX, startDisplayIndex) + } } return offsetQuery .limit(count) .findAll() } - private fun buildEventQuery(realm: Realm): RealmQuery { return if (initialEventId == null) { TimelineEventEntity @@ -542,33 +639,30 @@ internal class DefaultTimeline( } } - private fun findCurrentChunk(realm: Realm): ChunkEntity? { - return if (initialEventId == null) { - ChunkEntity.findLastLiveChunkFromRoom(realm, roomId) - } else { - ChunkEntity.findIncludingEvent(realm, initialEventId) - } - } - - private fun clearUnlinkedEvents(realm: Realm) { - realm.executeTransaction { - val unlinkedChunks = ChunkEntity - .where(it, roomId = roomId) - .equalTo("${ChunkEntityFields.TIMELINE_EVENTS.ROOT}.${EventEntityFields.IS_UNLINKED}", true) - .findAll() - unlinkedChunks.deleteAllFromRealm() - } - } - private fun fetchEvent(eventId: String) { val params = GetContextOfEventTask.Params(roomId, eventId) - contextOfEventTask.configureWith(params).executeBy(taskExecutor) + cancelableBag += contextOfEventTask.configureWith(params).executeBy(taskExecutor) } private fun postSnapshot() { - val snapshot = createSnapshot() - val runnable = Runnable { listener?.onUpdated(snapshot) } - debouncer.debounce("post_snapshot", runnable, 50) + BACKGROUND_HANDLER.post { + if (isReady.get().not()) { + return@post + } + updateLoadingStates(filteredEvents) + val snapshot = createSnapshot() + val runnable = Runnable { listener?.onUpdated(snapshot) } + debouncer.debounce("post_snapshot", runnable, 50) + } + } + + private fun clearAllValues() { + prevDisplayIndex = null + nextDisplayIndex = null + builtEvents.clear() + builtEventsIdMap.clear() + backwardsState.set(State()) + forwardsState.set(State()) } // Extension methods *************************************************************************** @@ -577,16 +671,6 @@ internal class DefaultTimeline( return if (this == Timeline.Direction.BACKWARDS) PaginationDirection.BACKWARDS else PaginationDirection.FORWARDS } - private fun RealmQuery.findFirst(direction: Timeline.Direction): TimelineEventEntity? { - return if (direction == Timeline.Direction.FORWARDS) { - sort(TimelineEventEntityFields.ROOT.DISPLAY_INDEX, Sort.DESCENDING) - } else { - sort(TimelineEventEntityFields.ROOT.DISPLAY_INDEX, Sort.ASCENDING) - } - .filterEventsWithSettings() - .findFirst() - } - private fun RealmQuery.filterEventsWithSettings(): RealmQuery { if (settings.filterTypes) { `in`(TimelineEventEntityFields.ROOT.TYPE, settings.allowedTypes.toTypedArray()) @@ -597,9 +681,10 @@ internal class DefaultTimeline( return this } + private data class State( + val hasReachedEnd: Boolean = false, + val hasMoreInCache: Boolean = true, + val isPaginating: Boolean = false, + val requestedPaginationCount: Int = 0 + ) } - -private data class PaginationState( - val isPaginating: Boolean = false, - val requestedCount: Int = 0 -) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/DefaultTimelineService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/DefaultTimelineService.kt index b6cc80ca78..3bd67d38c3 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/DefaultTimelineService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/DefaultTimelineService.kt @@ -26,7 +26,8 @@ import im.vector.matrix.android.api.session.room.timeline.Timeline import im.vector.matrix.android.api.session.room.timeline.TimelineEvent import im.vector.matrix.android.api.session.room.timeline.TimelineService import im.vector.matrix.android.api.session.room.timeline.TimelineSettings -import im.vector.matrix.android.internal.database.RealmLiveData +import im.vector.matrix.android.api.util.Optional +import im.vector.matrix.android.api.util.toOptional import im.vector.matrix.android.internal.database.mapper.ReadReceiptsSummaryMapper import im.vector.matrix.android.internal.database.mapper.TimelineEventMapper import im.vector.matrix.android.internal.database.model.TimelineEventEntity @@ -41,7 +42,8 @@ internal class DefaultTimelineService @AssistedInject constructor(@Assisted priv private val cryptoService: CryptoService, private val paginationTask: PaginationTask, private val timelineEventMapper: TimelineEventMapper, - private val readReceiptsSummaryMapper: ReadReceiptsSummaryMapper + private val readReceiptsSummaryMapper: ReadReceiptsSummaryMapper, + private val clearUnlinkedEventsTask: ClearUnlinkedEventsTask ) : TimelineService { @AssistedInject.Factory @@ -55,30 +57,32 @@ internal class DefaultTimelineService @AssistedInject constructor(@Assisted priv monarchy.realmConfiguration, taskExecutor, contextOfEventTask, + clearUnlinkedEventsTask, paginationTask, cryptoService, timelineEventMapper, settings, - TimelineHiddenReadReceipts(readReceiptsSummaryMapper, roomId, settings) + TimelineHiddenReadReceipts(readReceiptsSummaryMapper, roomId, settings), + TimelineHiddenReadMarker(roomId, settings) ) } override fun getTimeLineEvent(eventId: String): TimelineEvent? { return monarchy .fetchCopyMap({ - TimelineEventEntity.where(it, eventId = eventId).findFirst() - }, { entity, realm -> + TimelineEventEntity.where(it, roomId = roomId, eventId = eventId).findFirst() + }, { entity, _ -> timelineEventMapper.map(entity) }) } - override fun liveTimeLineEvent(eventId: String): LiveData { - val liveData = RealmLiveData(monarchy.realmConfiguration) { - TimelineEventEntity.where(it, eventId = eventId) - } + override fun getTimeLineEventLive(eventId: String): LiveData> { + val liveData = monarchy.findAllMappedWithChanges( + { TimelineEventEntity.where(it, roomId = roomId, eventId = eventId) }, + { timelineEventMapper.map(it) } + ) return Transformations.map(liveData) { events -> - events.firstOrNull()?.let { timelineEventMapper.map(it) } + events.firstOrNull().toOptional() } } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/EventContextResponse.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/EventContextResponse.kt index 782e3fe870..4dfe3e5c45 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/EventContextResponse.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/EventContextResponse.kt @@ -32,5 +32,4 @@ data class EventContextResponse( override val events: List get() = listOf(event) - } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/GetEventTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/GetEventTask.kt index 5fdee1b5af..8e097c50d9 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/GetEventTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/GetEventTask.kt @@ -35,4 +35,4 @@ internal class GetEventTask @Inject constructor(private val roomAPI: RoomAPI apiCall = roomAPI.getEvent(params.roomId, params.eventId) } } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/PaginationDirection.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/PaginationDirection.kt index f1194ed4e7..26bbe8071d 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/PaginationDirection.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/PaginationDirection.kt @@ -35,5 +35,4 @@ internal enum class PaginationDirection(val value: String) { BACKWARDS -> FORWARDS } } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/PaginationResponse.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/PaginationResponse.kt index adcfa2dfd4..0c57373d5b 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/PaginationResponse.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/PaginationResponse.kt @@ -26,4 +26,4 @@ internal data class PaginationResponse( @Json(name = "end") override val end: String? = null, @Json(name = "chunk") override val events: List = emptyList(), @Json(name = "state") override val stateEvents: List = emptyList() -) : TokenChunkEvent \ No newline at end of file +) : TokenChunkEvent diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/TimelineEventDecryptor.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/TimelineEventDecryptor.kt index 64d5f120da..967dd66397 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/TimelineEventDecryptor.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/TimelineEventDecryptor.kt @@ -26,9 +26,9 @@ import im.vector.matrix.android.internal.database.query.where import io.realm.Realm import io.realm.RealmConfiguration import timber.log.Timber +import java.util.concurrent.ExecutorService import java.util.concurrent.Executors - internal class TimelineEventDecryptor( private val realmConfiguration: RealmConfiguration, private val timelineId: String, @@ -38,64 +38,66 @@ internal class TimelineEventDecryptor( private val newSessionListener = object : NewSessionListener { override fun onNewSession(roomId: String?, senderKey: String, sessionId: String) { synchronized(unknownSessionsFailure) { - val toDecryptAgain = ArrayList() - unknownSessionsFailure[sessionId]?.let { eventIds -> - toDecryptAgain.addAll(eventIds) - } - if (toDecryptAgain.isNotEmpty()) { - unknownSessionsFailure[sessionId]?.clear() - toDecryptAgain.forEach { - requestDecryption(it) - } - } + unknownSessionsFailure[sessionId] + ?.toList() + .orEmpty() + .also { + unknownSessionsFailure[sessionId]?.clear() + } + }.forEach { + requestDecryption(it) } } - } - private val executor = Executors.newSingleThreadExecutor() + private var executor: ExecutorService? = null - private val existingRequests = HashSet() - private val unknownSessionsFailure = HashMap>() + // Set of eventIds which are currently decrypting + private val existingRequests = mutableSetOf() + // sessionId -> list of eventIds + private val unknownSessionsFailure = mutableMapOf>() fun start() { + executor = Executors.newSingleThreadExecutor() cryptoService.addNewSessionListener(newSessionListener) } fun destroy() { cryptoService.removeSessionListener(newSessionListener) - executor.shutdownNow() - unknownSessionsFailure.clear() - existingRequests.clear() + executor?.shutdownNow() + executor = null + synchronized(unknownSessionsFailure) { + unknownSessionsFailure.clear() + } + synchronized(existingRequests) { + existingRequests.clear() + } } fun requestDecryption(eventId: String) { - synchronized(existingRequests) { - if (existingRequests.contains(eventId)) { - return Unit.also { - Timber.d("Skip Decryption request for event ${eventId}, already requested") - } - } - existingRequests.add(eventId) - } synchronized(unknownSessionsFailure) { - unknownSessionsFailure.values.forEach { - if (it.contains(eventId)) return@synchronized Unit.also { - Timber.d("Skip Decryption request for event ${eventId}, unknown session") + for (eventIds in unknownSessionsFailure.values) { + if (eventId in eventIds) { + Timber.d("Skip Decryption request for event $eventId, unknown session") + return } } } - executor.execute { + synchronized(existingRequests) { + if (!existingRequests.add(eventId)) { + Timber.d("Skip Decryption request for event $eventId, already requested") + return + } + } + executor?.execute { Realm.getInstance(realmConfiguration).use { realm -> - realm.executeTransaction { - processDecryptRequest(eventId, it) - } + processDecryptRequest(eventId, realm) } } } private fun processDecryptRequest(eventId: String, realm: Realm) { - Timber.v("Decryption request for event ${eventId}") + Timber.v("Decryption request for event $eventId") val eventEntity = EventEntity.where(realm, eventId = eventId).findFirst() ?: return Unit.also { Timber.d("Decryption request for unknown message") @@ -103,20 +105,21 @@ internal class TimelineEventDecryptor( val event = eventEntity.asDomain() try { val result = cryptoService.decryptEvent(event, timelineId) - Timber.v("Successfully decrypted event ${eventId}") - eventEntity.setDecryptionResult(result) + Timber.v("Successfully decrypted event $eventId") + realm.executeTransaction { + eventEntity.setDecryptionResult(result) + } } catch (e: MXCryptoError) { - Timber.v("Failed to decrypt event ${eventId} ${e}") + Timber.v(e, "Failed to decrypt event $eventId") if (e is MXCryptoError.Base && e.errorType == MXCryptoError.ErrorType.UNKNOWN_INBOUND_SESSION_ID) { - //Keep track of unknown sessions to automatically try to decrypt on new session - eventEntity.decryptionErrorCode = e.errorType.name + // Keep track of unknown sessions to automatically try to decrypt on new session + realm.executeTransaction { + eventEntity.decryptionErrorCode = e.errorType.name + } event.content?.toModel()?.let { content -> content.sessionId?.let { sessionId -> synchronized(unknownSessionsFailure) { - val list = unknownSessionsFailure[sessionId] - ?: ArrayList().also { - unknownSessionsFailure[sessionId] = it - } + val list = unknownSessionsFailure.getOrPut(sessionId) { mutableSetOf() } list.add(eventId) } } @@ -130,4 +133,4 @@ internal class TimelineEventDecryptor( } } } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/TimelineHiddenReadMarker.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/TimelineHiddenReadMarker.kt new file mode 100644 index 0000000000..4f80883bf9 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/TimelineHiddenReadMarker.kt @@ -0,0 +1,133 @@ +/* + + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + + */ + +package im.vector.matrix.android.internal.session.room.timeline + +import im.vector.matrix.android.api.session.room.timeline.TimelineSettings +import im.vector.matrix.android.internal.database.model.ReadMarkerEntity +import im.vector.matrix.android.internal.database.model.ReadMarkerEntityFields +import im.vector.matrix.android.internal.database.model.TimelineEventEntity +import im.vector.matrix.android.internal.database.model.TimelineEventEntityFields +import im.vector.matrix.android.internal.database.query.FilterContent +import im.vector.matrix.android.internal.database.query.where +import io.realm.OrderedRealmCollectionChangeListener +import io.realm.Realm +import io.realm.RealmQuery +import io.realm.RealmResults + +/** + * This class is responsible for handling the read marker for hidden events. + * When an hidden event has read marker, we want to transfer it on the first older displayed event. + * It has to be used in [DefaultTimeline] and we should call the [start] and [dispose] methods to properly handle realm subscription. + */ +internal class TimelineHiddenReadMarker constructor(private val roomId: String, + private val settings: TimelineSettings) { + + interface Delegate { + fun rebuildEvent(eventId: String, hasReadMarker: Boolean): Boolean + fun onReadMarkerUpdated() + } + + private var previousDisplayedEventId: String? = null + private var hiddenReadMarker: RealmResults? = null + + private lateinit var filteredEvents: RealmResults + private lateinit var nonFilteredEvents: RealmResults + private lateinit var delegate: Delegate + + private val readMarkerListener = OrderedRealmCollectionChangeListener> { readMarkers, changeSet -> + if (!readMarkers.isLoaded || !readMarkers.isValid) { + return@OrderedRealmCollectionChangeListener + } + var hasChange = false + if (changeSet.deletions.isNotEmpty()) { + previousDisplayedEventId?.also { + hasChange = delegate.rebuildEvent(it, false) + previousDisplayedEventId = null + } + } + val readMarker = readMarkers.firstOrNull() ?: return@OrderedRealmCollectionChangeListener + val hiddenEvent = readMarker.timelineEvent?.firstOrNull() + ?: return@OrderedRealmCollectionChangeListener + + val isLoaded = nonFilteredEvents.where() + .equalTo(TimelineEventEntityFields.EVENT_ID, hiddenEvent.eventId) + .findFirst() != null + + val displayIndex = hiddenEvent.root?.displayIndex + if (isLoaded && displayIndex != null) { + // Then we are looking for the first displayable event after the hidden one + val firstDisplayedEvent = filteredEvents.where() + .lessThanOrEqualTo(TimelineEventEntityFields.ROOT.DISPLAY_INDEX, displayIndex) + .findFirst() + + // If we find one, we should rebuild this one with marker + if (firstDisplayedEvent != null) { + previousDisplayedEventId = firstDisplayedEvent.eventId + hasChange = delegate.rebuildEvent(firstDisplayedEvent.eventId, true) + } + } + if (hasChange) { + delegate.onReadMarkerUpdated() + } + } + + /** + * Start the realm query subscription. Has to be called on an HandlerThread + */ + fun start(realm: Realm, + filteredEvents: RealmResults, + nonFilteredEvents: RealmResults, + delegate: Delegate) { + this.filteredEvents = filteredEvents + this.nonFilteredEvents = nonFilteredEvents + this.delegate = delegate + // We are looking for read receipts set on hidden events. + // We only accept those with a timelineEvent (so coming from pagination/sync). + hiddenReadMarker = ReadMarkerEntity.where(realm, roomId = roomId) + .isNotEmpty(ReadMarkerEntityFields.TIMELINE_EVENT) + .filterReceiptsWithSettings() + .findAllAsync() + .also { it.addChangeListener(readMarkerListener) } + } + + /** + * Dispose the realm query subscription. Has to be called on an HandlerThread + */ + fun dispose() { + this.hiddenReadMarker?.removeAllChangeListeners() + } + + /** + * We are looking for readMarker related to filtered events. So, it's the opposite of [DefaultTimeline.filterEventsWithSettings] method. + */ + private fun RealmQuery.filterReceiptsWithSettings(): RealmQuery { + beginGroup() + if (settings.filterTypes) { + not().`in`("${ReadMarkerEntityFields.TIMELINE_EVENT}.${TimelineEventEntityFields.ROOT.TYPE}", settings.allowedTypes.toTypedArray()) + } + if (settings.filterTypes && settings.filterEdits) { + or() + } + if (settings.filterEdits) { + like("${ReadMarkerEntityFields.TIMELINE_EVENT}.${TimelineEventEntityFields.ROOT.CONTENT}", FilterContent.EDIT_TYPE) + } + endGroup() + return this + } +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/TimelineHiddenReadReceipts.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/TimelineHiddenReadReceipts.kt index 5658210302..1a1f90c7a3 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/TimelineHiddenReadReceipts.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/TimelineHiddenReadReceipts.kt @@ -49,15 +49,19 @@ internal class TimelineHiddenReadReceipts constructor(private val readReceiptsSu private val correctedReadReceiptsByEvent = HashMap>() private lateinit var hiddenReadReceipts: RealmResults - private lateinit var liveEvents: RealmResults + private lateinit var nonFilteredEvents: RealmResults + private lateinit var filteredEvents: RealmResults private lateinit var delegate: Delegate private val hiddenReadReceiptsListener = OrderedRealmCollectionChangeListener> { collection, changeSet -> + if (!collection.isLoaded || !collection.isValid) { + return@OrderedRealmCollectionChangeListener + } var hasChange = false // Deletion here means we don't have any readReceipts for the given hidden events changeSet.deletions.forEach { - val eventId = correctedReadReceiptsEventByIndex[it] - val timelineEvent = liveEvents.where() + val eventId = correctedReadReceiptsEventByIndex.get(it, "") + val timelineEvent = filteredEvents.where() .equalTo(TimelineEventEntityFields.EVENT_ID, eventId) .findFirst() @@ -67,12 +71,16 @@ internal class TimelineHiddenReadReceipts constructor(private val readReceiptsSu } correctedReadReceiptsEventByIndex.clear() correctedReadReceiptsByEvent.clear() - hiddenReadReceipts.forEachIndexed { index, summary -> - val timelineEvent = summary?.timelineEvent?.firstOrNull() - val displayIndex = timelineEvent?.root?.displayIndex - if (displayIndex != null) { + for (index in 0 until hiddenReadReceipts.size) { + val summary = hiddenReadReceipts[index] ?: continue + val timelineEvent = summary.timelineEvent?.firstOrNull() ?: continue + val isLoaded = nonFilteredEvents.where() + .equalTo(TimelineEventEntityFields.EVENT_ID, timelineEvent.eventId).findFirst() != null + val displayIndex = timelineEvent.root?.displayIndex + + if (isLoaded && displayIndex != null) { // Then we are looking for the first displayable event after the hidden one - val firstDisplayedEvent = liveEvents.where() + val firstDisplayedEvent = filteredEvents.where() .lessThanOrEqualTo(TimelineEventEntityFields.ROOT.DISPLAY_INDEX, displayIndex) .findFirst() @@ -103,8 +111,12 @@ internal class TimelineHiddenReadReceipts constructor(private val readReceiptsSu /** * Start the realm query subscription. Has to be called on an HandlerThread */ - fun start(realm: Realm, liveEvents: RealmResults, delegate: Delegate) { - this.liveEvents = liveEvents + fun start(realm: Realm, + filteredEvents: RealmResults, + nonFilteredEvents: RealmResults, + delegate: Delegate) { + this.filteredEvents = filteredEvents + this.nonFilteredEvents = nonFilteredEvents this.delegate = delegate // We are looking for read receipts set on hidden events. // We only accept those with a timelineEvent (so coming from pagination/sync). @@ -120,7 +132,9 @@ internal class TimelineHiddenReadReceipts constructor(private val readReceiptsSu * Dispose the realm query subscription. Has to be called on an HandlerThread */ fun dispose() { - this.hiddenReadReceipts.removeAllChangeListeners() + if (this::hiddenReadReceipts.isInitialized) { + this.hiddenReadReceipts.removeAllChangeListeners() + } } /** @@ -130,7 +144,6 @@ internal class TimelineHiddenReadReceipts constructor(private val readReceiptsSu return correctedReadReceiptsByEvent[eventId] } - /** * We are looking for receipts related to filtered events. So, it's the opposite of [DefaultTimeline.filterEventsWithSettings] method. */ @@ -148,6 +161,4 @@ internal class TimelineHiddenReadReceipts constructor(private val readReceiptsSu endGroup() return this } - - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/TimelineSendEventWorkCommon.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/TimelineSendEventWorkCommon.kt index 575c066243..f6f894d860 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/TimelineSendEventWorkCommon.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/TimelineSendEventWorkCommon.kt @@ -22,7 +22,6 @@ import im.vector.matrix.android.internal.worker.WorkManagerUtil.matrixOneTimeWor import im.vector.matrix.android.internal.worker.startChain import java.util.concurrent.TimeUnit - private const val SEND_WORK = "SEND_WORK" private const val BACKOFF_DELAY = 10_000L @@ -74,4 +73,4 @@ internal object TimelineSendEventWorkCommon { fun cancelAllWorks(context: Context, roomId: String) { WorkManager.getInstance(context).cancelUniqueWork(buildWorkName(roomId)) } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/TokenChunkEvent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/TokenChunkEvent.kt index 97b8f793b3..95edf9bc49 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/TokenChunkEvent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/TokenChunkEvent.kt @@ -23,4 +23,4 @@ internal interface TokenChunkEvent { val end: String? val events: List val stateEvents: List -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/TokenChunkEventPersistor.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/TokenChunkEventPersistor.kt index af845040ae..0d9fb4e9e6 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/TokenChunkEventPersistor.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/TokenChunkEventPersistor.kt @@ -100,19 +100,19 @@ internal class TokenChunkEventPersistor @Inject constructor(private val monarchy enum class Result { SHOULD_FETCH_MORE, + REACHED_END, SUCCESS } 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") val roomEntity = RoomEntity.where(realm, roomId).findFirst() - ?: realm.createObject(roomId) + ?: realm.createObject(roomId) val nextToken: String? val prevToken: String? @@ -124,10 +124,8 @@ internal class TokenChunkEventPersistor @Inject constructor(private val monarchy prevToken = receivedChunk.end } - if (ChunkEntity.find(realm, roomId, nextToken = nextToken) != null || ChunkEntity.find(realm, roomId, prevToken = prevToken) != null) { - Timber.v("Already inserted - SKIP") - return@awaitTransaction - } + val shouldSkip = ChunkEntity.find(realm, roomId, nextToken = nextToken) != null + || ChunkEntity.find(realm, roomId, prevToken = prevToken) != null val prevChunk = ChunkEntity.find(realm, roomId, nextToken = prevToken) val nextChunk = ChunkEntity.find(realm, roomId, prevToken = nextToken) @@ -141,12 +139,12 @@ internal class TokenChunkEventPersistor @Inject constructor(private val monarchy } else { nextChunk?.apply { this.prevToken = prevToken } } - ?: ChunkEntity.create(realm, prevToken, nextToken) + ?: ChunkEntity.create(realm, prevToken, nextToken) if (receivedChunk.events.isEmpty() && receivedChunk.end == receivedChunk.start) { Timber.v("Reach end of $roomId") currentChunk.isLastBackward = true - } else { + } else if (!shouldSkip) { Timber.v("Add ${receivedChunk.events.size} events in chunk(${currentChunk.nextToken} | ${currentChunk.prevToken}") val eventIds = ArrayList(receivedChunk.events.size) for (event in receivedChunk.events) { @@ -163,8 +161,8 @@ internal class TokenChunkEventPersistor @Inject constructor(private val monarchy currentChunk = handleMerge(roomEntity, direction, currentChunk, nextChunk) } else { val newEventIds = receivedChunk.events.mapNotNull { it.eventId } - ChunkEntity - .findAllIncludingEvents(realm, newEventIds) + val overlappedChunks = ChunkEntity.findAllIncludingEvents(realm, newEventIds) + overlappedChunks .filter { it != currentChunk } .forEach { overlapped -> currentChunk = handleMerge(roomEntity, direction, currentChunk, overlapped) @@ -180,8 +178,12 @@ internal class TokenChunkEventPersistor @Inject constructor(private val monarchy currentChunk.updateSenderDataFor(eventIds) } } - return if (receivedChunk.events.isEmpty() && receivedChunk.stateEvents.isEmpty() && receivedChunk.start != receivedChunk.end) { - Result.SHOULD_FETCH_MORE + return if (receivedChunk.events.isEmpty()) { + if (receivedChunk.start != receivedChunk.end) { + Result.SHOULD_FETCH_MORE + } else { + Result.REACHED_END + } } else { Result.SUCCESS } @@ -191,10 +193,9 @@ internal class TokenChunkEventPersistor @Inject constructor(private val monarchy direction: PaginationDirection, currentChunk: ChunkEntity, otherChunk: ChunkEntity): ChunkEntity { - // We always merge the bottom chunk into top chunk, so we are always merging backwards Timber.v("Merge ${currentChunk.prevToken} | ${currentChunk.nextToken} with ${otherChunk.prevToken} | ${otherChunk.nextToken}") - return if (direction == PaginationDirection.BACKWARDS) { + return if (direction == PaginationDirection.BACKWARDS && !otherChunk.isLastForward) { currentChunk.merge(roomEntity.roomId, otherChunk, PaginationDirection.BACKWARDS) roomEntity.deleteOnCascade(otherChunk) currentChunk @@ -204,5 +205,4 @@ internal class TokenChunkEventPersistor @Inject constructor(private val monarchy otherChunk } } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/tombstone/RoomTombstoneEventLiveObserver.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/tombstone/RoomTombstoneEventLiveObserver.kt index d71b32ef8b..301c383a6d 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/tombstone/RoomTombstoneEventLiveObserver.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/tombstone/RoomTombstoneEventLiveObserver.kt @@ -68,9 +68,7 @@ internal class RoomTombstoneEventLiveObserver @Inject constructor(@SessionDataba predecessorRoomSummary.versioningState = VersioningState.UPGRADED_ROOM_NOT_JOINED } realm.insertOrUpdate(predecessorRoomSummary) - } } } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/securestorage/SecretStoringUtils.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/securestorage/SecretStoringUtils.kt index 6192aaf148..260f98d97f 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/securestorage/SecretStoringUtils.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/securestorage/SecretStoringUtils.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package im.vector.matrix.android.internal.session.securestorage import android.content.Context @@ -38,7 +40,6 @@ import javax.crypto.spec.SecretKeySpec import javax.inject.Inject import javax.security.auth.x500.X500Principal - /** * Offers simple methods to securely store secrets in an Android Application. * The encryption keys are randomly generated and securely managed by the key store, thus your secrets @@ -65,7 +66,7 @@ import javax.security.auth.x500.X500Principal * //This can be stored anywhere e.g. encoded in b64 and stored in preference for example * * //to get back the secret, just call - * val kDecripted = SecretStoringUtils.loadSecureSecret(KEncrypted!!, "myAlias", context) + * val kDecrypted = SecretStoringUtils.loadSecureSecret(KEncrypted!!, "myAlias", context) * * * You can also just use this utility to store a secret key, and use any encryption algorithm that you want. @@ -148,13 +149,12 @@ internal class SecretStoringUtils @Inject constructor(private val context: Conte } } - @RequiresApi(Build.VERSION_CODES.M) private fun getOrGenerateSymmetricKeyForAliasM(alias: String): SecretKey { val secretKeyEntry = (keyStore.getEntry(alias, null) as? KeyStore.SecretKeyEntry) ?.secretKey if (secretKeyEntry == null) { - //we generate it + // we generate it val generator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore") val keyGenSpec = KeyGenParameterSpec.Builder(alias, KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT) @@ -169,7 +169,7 @@ internal class SecretStoringUtils @Inject constructor(private val context: Conte } /* - Symetric Key Generation is only available in M, so before M the idea is to: + Symmetric Key Generation is only available in M, so before M the idea is to: - Generate a pair of RSA keys; - Generate a random AES key; - Encrypt the AES key using the RSA public key; @@ -190,19 +190,17 @@ internal class SecretStoringUtils @Inject constructor(private val context: Conte .setAlias(alias) .setSubject(X500Principal("CN=$alias")) .setSerialNumber(BigInteger.TEN) - //.setEncryptionRequired() requires that the phone as a pin/schema + // .setEncryptionRequired() requires that the phone as a pin/schema .setStartDate(start.time) .setEndDate(end.time) .build() - KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, ANDROID_KEY_STORE).run { + KeyPairGenerator.getInstance("RSA" /*KeyProperties.KEY_ALGORITHM_RSA*/, ANDROID_KEY_STORE).run { initialize(spec) generateKeyPair() } return (keyStore.getEntry(alias, null) as KeyStore.PrivateKeyEntry) - } - @RequiresApi(Build.VERSION_CODES.M) fun encryptStringM(text: String, keyAlias: String): ByteArray? { val secretKey = getOrGenerateSymmetricKeyForAliasM(keyAlias) @@ -210,7 +208,7 @@ internal class SecretStoringUtils @Inject constructor(private val context: Conte val cipher = Cipher.getInstance(AES_MODE) cipher.init(Cipher.ENCRYPT_MODE, secretKey) val iv = cipher.iv - //we happen the iv to the final result + // we happen the iv to the final result val encryptedBytes: ByteArray = cipher.doFinal(text.toByteArray(Charsets.UTF_8)) return formatMMake(iv, encryptedBytes) } @@ -230,12 +228,12 @@ internal class SecretStoringUtils @Inject constructor(private val context: Conte @RequiresApi(Build.VERSION_CODES.KITKAT) private fun encryptStringK(text: String, keyAlias: String): ByteArray? { - //we generate a random symetric key + // we generate a random symmetric key val key = ByteArray(16) secureRandom.nextBytes(key) val sKey = SecretKeySpec(key, "AES") - //we encrypt this key thanks to the key store + // we encrypt this key thanks to the key store val encryptedKey = rsaEncrypt(keyAlias, key) val cipher = Cipher.getInstance(AES_MODE) @@ -263,7 +261,6 @@ internal class SecretStoringUtils @Inject constructor(private val context: Conte } private fun decryptForOldDevicesNotGood(data: ByteArray, keyAlias: String): String? { - val (salt, iv, encrypted) = format2Extract(ByteArrayInputStream(data)) val factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256") val spec = PBEKeySpec(keyAlias.toCharArray(), salt, 10_000, 128) @@ -282,10 +279,9 @@ internal class SecretStoringUtils @Inject constructor(private val context: Conte @RequiresApi(Build.VERSION_CODES.KITKAT) private fun decryptStringK(data: ByteArray, keyAlias: String): String? { - val (encryptedKey, iv, encrypted) = format1Extract(ByteArrayInputStream(data)) - //we need to decrypt the key + // we need to decrypt the key val sKeyBytes = rsaDecrypt(keyAlias, ByteArrayInputStream(encryptedKey)) val cipher = Cipher.getInstance(AES_MODE) val spec = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) IvParameterSpec(iv) else GCMParameterSpec(128, iv) @@ -307,7 +303,7 @@ internal class SecretStoringUtils @Inject constructor(private val context: Conte ObjectOutputStream(bos1).use { it.writeObject(writeObject) } - //Have to do it like that if i encapsulate the outputstream, the cipher could fail saying reuse IV + // Have to do it like that if i encapsulate the output stream, the cipher could fail saying reuse IV val doFinal = cipher.doFinal(bos1.toByteArray()) output.write(FORMAT_API_M.toInt()) output.write(iv.size) @@ -317,12 +313,12 @@ internal class SecretStoringUtils @Inject constructor(private val context: Conte @RequiresApi(Build.VERSION_CODES.KITKAT) private fun saveSecureObjectK(keyAlias: String, output: OutputStream, writeObject: Any) { - //we generate a random symetric key + // we generate a random symmetric key val key = ByteArray(16) secureRandom.nextBytes(key) val sKey = SecretKeySpec(key, "AES") - //we encrypt this key thanks to the key store + // we encrypt this key thanks to the key store val encryptedKey = rsaEncrypt(keyAlias, key) val cipher = Cipher.getInstance(AES_MODE) @@ -351,7 +347,6 @@ internal class SecretStoringUtils @Inject constructor(private val context: Conte val tmp = factory.generateSecret(PBEKeySpec(keyAlias.toCharArray(), salt, 10000, 128)) val secretKey = SecretKeySpec(tmp.encoded, "AES") - val cipher = Cipher.getInstance(AES_MODE) cipher.init(Cipher.ENCRYPT_MODE, secretKey) val iv = cipher.iv @@ -360,7 +355,7 @@ internal class SecretStoringUtils @Inject constructor(private val context: Conte ObjectOutputStream(bos1).use { it.writeObject(writeObject) } - //Have to do it like that if i encapsulate the outputstream, the cipher could fail saying reuse IV + // Have to do it like that if i encapsulate the output stream, the cipher could fail saying reuse IV val doFinal = cipher.doFinal(bos1.toByteArray()) output.write(FORMAT_2.toInt()) @@ -405,19 +400,18 @@ internal class SecretStoringUtils @Inject constructor(private val context: Conte CipherInputStream(inputStream, cipher).use { cipherInputStream -> ObjectInputStream(cipherInputStream).use { val readObject = it.readObject() + @Suppress("UNCHECKED_CAST") return readObject as? T } } - } @RequiresApi(Build.VERSION_CODES.KITKAT) @Throws(IOException::class) private fun loadSecureObjectK(keyAlias: String, inputStream: InputStream): T? { - val (encryptedKey, iv, encrypted) = format1Extract(inputStream) - //we need to decrypt the key + // we need to decrypt the key val sKeyBytes = rsaDecrypt(keyAlias, ByteArrayInputStream(encryptedKey)) val cipher = Cipher.getInstance(AES_MODE) val spec = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) IvParameterSpec(iv) else GCMParameterSpec(128, iv) @@ -428,6 +422,7 @@ internal class SecretStoringUtils @Inject constructor(private val context: Conte CipherInputStream(encIS, cipher).use { cipherInputStream -> ObjectInputStream(cipherInputStream).use { val readObject = it.readObject() + @Suppress("UNCHECKED_CAST") return readObject as? T } } @@ -440,7 +435,7 @@ internal class SecretStoringUtils @Inject constructor(private val context: Conte val factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256") val tmp = factory.generateSecret(PBEKeySpec(keyAlias.toCharArray(), salt, 10000, 128)) val sKey = SecretKeySpec(tmp.encoded, "AES") - //we need to decrypt the key + // we need to decrypt the key val cipher = Cipher.getInstance(AES_MODE) val spec = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) IvParameterSpec(iv) else GCMParameterSpec(128, iv) @@ -449,14 +444,14 @@ internal class SecretStoringUtils @Inject constructor(private val context: Conte val encIS = ByteArrayInputStream(encrypted) CipherInputStream(encIS, cipher).use { - ObjectInputStream(it).use { - val readObject = it.readObject() + ObjectInputStream(it).use { ois -> + val readObject = ois.readObject() + @Suppress("UNCHECKED_CAST") return readObject as? T } } } - @RequiresApi(Build.VERSION_CODES.KITKAT) @Throws(Exception::class) private fun rsaEncrypt(alias: String, secret: ByteArray): ByteArray { @@ -466,9 +461,9 @@ internal class SecretStoringUtils @Inject constructor(private val context: Conte inputCipher.init(Cipher.ENCRYPT_MODE, privateKeyEntry.certificate.publicKey) val outputStream = ByteArrayOutputStream() - val cipherOutputStream = CipherOutputStream(outputStream, inputCipher) - cipherOutputStream.write(secret) - cipherOutputStream.close() + CipherOutputStream(outputStream, inputCipher).use { + it.write(secret) + } return outputStream.toByteArray() } @@ -562,4 +557,4 @@ internal class SecretStoringUtils @Inject constructor(private val context: Conte val encrypted = bis.readBytes() return Triple(salt, iv, encrypted) } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/signout/DefaultSignOutService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/signout/DefaultSignOutService.kt index 2463a5ade5..b48ac2c78a 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/signout/DefaultSignOutService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/signout/DefaultSignOutService.kt @@ -32,5 +32,4 @@ internal class DefaultSignOutService @Inject constructor(private val signOutTask } .executeBy(taskExecutor) } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/signout/SignOutAPI.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/signout/SignOutAPI.kt index cf45c8d996..2f19fee847 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/signout/SignOutAPI.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/signout/SignOutAPI.kt @@ -27,5 +27,4 @@ internal interface SignOutAPI { */ @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "logout") fun signOut(): Call - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/signout/SignOutModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/signout/SignOutModule.kt index c123dd01ca..c55c82274d 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/signout/SignOutModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/signout/SignOutModule.kt @@ -41,5 +41,4 @@ internal abstract class SignOutModule { @Binds abstract fun bindSignOutService(signOutService: DefaultSignOutService): SignOutService - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/signout/SignOutTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/signout/SignOutTask.kt index 68536d4f50..fbeabff0b5 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/signout/SignOutTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/signout/SignOutTask.kt @@ -72,4 +72,4 @@ internal class DefaultSignOutTask @Inject constructor(private val context: Conte realmKeysUtils.clear(SessionModule.DB_ALIAS_PREFIX + userMd5) realmKeysUtils.clear(CryptoModule.DB_ALIAS_PREFIX + userMd5) } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/CryptoSyncHandler.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/CryptoSyncHandler.kt index 945f344036..91397fae7e 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/CryptoSyncHandler.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/CryptoSyncHandler.kt @@ -16,7 +16,6 @@ package im.vector.matrix.android.internal.session.sync -import android.text.TextUtils import im.vector.matrix.android.api.session.crypto.MXCryptoError import im.vector.matrix.android.api.session.events.model.Event import im.vector.matrix.android.api.session.events.model.EventType @@ -32,7 +31,6 @@ import im.vector.matrix.android.internal.session.sync.model.ToDeviceSyncResponse import timber.log.Timber import javax.inject.Inject - internal class CryptoSyncHandler @Inject constructor(private val cryptoService: DefaultCryptoService, private val sasVerificationService: DefaultSasVerificationService) { @@ -42,9 +40,9 @@ internal class CryptoSyncHandler @Inject constructor(private val cryptoService: initialSyncProgressService?.reportProgress(((index / total.toFloat()) * 100).toInt()) // Decrypt event if necessary decryptEvent(event, null) - if (TextUtils.equals(event.getClearType(), EventType.MESSAGE) + if (event.getClearType() == EventType.MESSAGE && event.getClearContent()?.toModel()?.type == "m.bad.encrypted") { - Timber.e("## handleToDeviceEvent() : Warning: Unable to decrypt to-device event : " + event.content) + Timber.e("## handleToDeviceEvent() : Warning: Unable to decrypt to-device event : ${event.content}") } else { sasVerificationService.onToDeviceEvent(event) cryptoService.onToDeviceEvent(event) @@ -56,7 +54,6 @@ internal class CryptoSyncHandler @Inject constructor(private val cryptoService: cryptoService.onSyncCompleted(syncResponse) } - /** * Decrypt an encrypted event * @@ -70,7 +67,7 @@ internal class CryptoSyncHandler @Inject constructor(private val cryptoService: try { result = cryptoService.decryptEvent(event, timelineId ?: "") } catch (exception: MXCryptoError) { - event.mCryptoError = (exception as? MXCryptoError.Base)?.errorType //setCryptoError(exception.cryptoError) + event.mCryptoError = (exception as? MXCryptoError.Base)?.errorType // setCryptoError(exception.cryptoError) } if (null != result) { @@ -78,7 +75,7 @@ internal class CryptoSyncHandler @Inject constructor(private val cryptoService: // payload = result.clearEvent, // keysClaimed = map // ) - //TODO persist that? + // TODO persist that? event.mxDecryptionResult = OlmDecryptionResult( payload = result.clearEvent, senderKey = result.senderCurve25519Key, @@ -92,4 +89,4 @@ internal class CryptoSyncHandler @Inject constructor(private val cryptoService: return false } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/GroupSyncHandler.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/GroupSyncHandler.kt index 9355384ef5..2ca9b6cccc 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/GroupSyncHandler.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/GroupSyncHandler.kt @@ -25,6 +25,7 @@ import im.vector.matrix.android.internal.session.DefaultInitialSyncProgressServi import im.vector.matrix.android.internal.session.mapWithProgress import im.vector.matrix.android.internal.session.sync.model.GroupsSyncResponse import im.vector.matrix.android.internal.session.sync.model.InvitedGroupSync +import im.vector.matrix.android.internal.util.awaitTransaction import io.realm.Realm import javax.inject.Inject @@ -36,8 +37,8 @@ internal class GroupSyncHandler @Inject constructor(private val monarchy: Monarc data class LEFT(val data: Map) : HandlingStrategy() } - fun handle(roomsSyncResponse: GroupsSyncResponse, reporter: DefaultInitialSyncProgressService? = null) { - monarchy.runTransactionSync { realm -> + suspend fun handle(roomsSyncResponse: GroupsSyncResponse, reporter: DefaultInitialSyncProgressService? = null) { + monarchy.awaitTransaction { realm -> handleGroupSync(realm, HandlingStrategy.JOINED(roomsSyncResponse.join), reporter) handleGroupSync(realm, HandlingStrategy.INVITED(roomsSyncResponse.invite), reporter) handleGroupSync(realm, HandlingStrategy.LEFT(roomsSyncResponse.leave), reporter) @@ -62,7 +63,6 @@ internal class GroupSyncHandler @Inject constructor(private val monarchy: Monarc handlingStrategy.data.mapWithProgress(reporter, R.string.initial_sync_start_importing_account_groups, 0.1f) { handleLeftGroup(realm, it.key) } - } /** Note: [im.vector.matrix.android.internal.session.group.GroupSummaryUpdater] is observing changes */ @@ -81,7 +81,6 @@ internal class GroupSyncHandler @Inject constructor(private val monarchy: Monarc val groupEntity = GroupEntity.where(realm, groupId).findFirst() ?: GroupEntity(groupId) groupEntity.membership = Membership.INVITE return groupEntity - } private fun handleLeftGroup(realm: Realm, @@ -90,4 +89,4 @@ internal class GroupSyncHandler @Inject constructor(private val monarchy: Monarc groupEntity.membership = Membership.LEAVE return groupEntity } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/ReadReceiptHandler.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/ReadReceiptHandler.kt index e61e81dd16..62fbd42ed5 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/ReadReceiptHandler.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/ReadReceiptHandler.kt @@ -25,8 +25,7 @@ import io.realm.Realm import timber.log.Timber import javax.inject.Inject - -// the receipts dictionnaries +// the receipts dictionaries // key : $EventId // value : dict key $UserId // value dict key ts @@ -38,6 +37,21 @@ private const val TIMESTAMP_KEY = "ts" internal class ReadReceiptHandler @Inject constructor() { + companion object { + + fun createContent(userId: String, eventId: String): ReadReceiptContent { + return mapOf( + eventId to mapOf( + READ_KEY to mapOf( + userId to mapOf( + TIMESTAMP_KEY to System.currentTimeMillis().toDouble() + ) + ) + ) + ) + } + } + fun handle(realm: Realm, roomId: String, content: ReadReceiptContent?, isInitialSync: Boolean) { if (content == null) { return @@ -57,7 +71,6 @@ internal class ReadReceiptHandler @Inject constructor() { } } - private fun initialSyncStrategy(realm: Realm, roomId: String, content: ReadReceiptContent) { val readReceiptSummaries = ArrayList() for ((eventId, receiptDict) in content) { @@ -97,6 +110,4 @@ internal class ReadReceiptHandler @Inject constructor() { } } } - - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/RoomFullyReadHandler.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/RoomFullyReadHandler.kt new file mode 100644 index 0000000000..853774460f --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/RoomFullyReadHandler.kt @@ -0,0 +1,56 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.matrix.android.internal.session.sync + +import im.vector.matrix.android.internal.database.model.EventEntity +import im.vector.matrix.android.internal.session.room.read.FullyReadContent +import im.vector.matrix.android.internal.database.model.ReadMarkerEntity +import im.vector.matrix.android.internal.database.model.RoomSummaryEntity +import im.vector.matrix.android.internal.database.model.TimelineEventEntity +import im.vector.matrix.android.internal.database.model.TimelineEventEntityFields +import im.vector.matrix.android.internal.database.query.getOrCreate +import im.vector.matrix.android.internal.database.query.where +import io.realm.Realm +import timber.log.Timber +import javax.inject.Inject + +internal class RoomFullyReadHandler @Inject constructor() { + + fun handle(realm: Realm, roomId: String, content: FullyReadContent?) { + if (content == null) { + return + } + Timber.v("Handle for roomId: $roomId eventId: ${content.eventId}") + + RoomSummaryEntity.getOrCreate(realm, roomId).apply { + readMarkerId = content.eventId + } + // Remove the old markers if any + val oldReadMarkerEvents = TimelineEventEntity + .where(realm, roomId = roomId, linkFilterMode = EventEntity.LinkFilterMode.BOTH) + .isNotNull(TimelineEventEntityFields.READ_MARKER.`$`) + .findAll() + + oldReadMarkerEvents.forEach { it.readMarker = null } + val readMarkerEntity = ReadMarkerEntity.getOrCreate(realm, roomId).apply { + this.eventId = content.eventId + } + // Attach to timelineEvent if known + val timelineEventEntities = TimelineEventEntity.where(realm, roomId = roomId, eventId = content.eventId).findAll() + timelineEventEntities.forEach { it.readMarker = readMarkerEntity } + } +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/RoomSyncHandler.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/RoomSyncHandler.kt index 11ebff7048..5fb25834c0 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/RoomSyncHandler.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/RoomSyncHandler.kt @@ -37,11 +37,13 @@ import im.vector.matrix.android.internal.session.mapWithProgress import im.vector.matrix.android.internal.session.notification.DefaultPushRuleService import im.vector.matrix.android.internal.session.notification.ProcessEventForPushTask import im.vector.matrix.android.internal.session.room.RoomSummaryUpdater +import im.vector.matrix.android.internal.session.room.read.FullyReadContent import im.vector.matrix.android.internal.session.room.timeline.PaginationDirection import im.vector.matrix.android.internal.session.sync.model.* import im.vector.matrix.android.internal.session.user.UserEntityFactory import im.vector.matrix.android.internal.task.TaskExecutor import im.vector.matrix.android.internal.task.configureWith +import im.vector.matrix.android.internal.util.awaitTransaction import io.realm.Realm import io.realm.kotlin.createObject import timber.log.Timber @@ -51,6 +53,7 @@ internal class RoomSyncHandler @Inject constructor(private val monarchy: Monarch private val readReceiptHandler: ReadReceiptHandler, private val roomSummaryUpdater: RoomSummaryUpdater, private val roomTagHandler: RoomTagHandler, + private val roomFullyReadHandler: RoomFullyReadHandler, private val cryptoService: DefaultCryptoService, private val tokenStore: SyncTokenStore, private val pushRuleService: DefaultPushRuleService, @@ -63,16 +66,14 @@ internal class RoomSyncHandler @Inject constructor(private val monarchy: Monarch data class LEFT(val data: Map) : HandlingStrategy() } - fun handle(roomsSyncResponse: RoomsSyncResponse, isInitialSync: Boolean, reporter: DefaultInitialSyncProgressService? = null) { - monarchy.runTransactionSync { realm -> + suspend fun handle(roomsSyncResponse: RoomsSyncResponse, isInitialSync: Boolean, reporter: DefaultInitialSyncProgressService? = null) { + monarchy.awaitTransaction { realm -> handleRoomSync(realm, HandlingStrategy.JOINED(roomsSyncResponse.join), isInitialSync, reporter) handleRoomSync(realm, HandlingStrategy.INVITED(roomsSyncResponse.invite), isInitialSync, reporter) handleRoomSync(realm, HandlingStrategy.LEFT(roomsSyncResponse.leave), isInitialSync, reporter) } - - //handle event for bing rule checks + // handle event for bing rule checks checkPushRules(roomsSyncResponse) - } private fun checkPushRules(roomsSyncResponse: RoomsSyncResponse) { @@ -80,7 +81,7 @@ internal class RoomSyncHandler @Inject constructor(private val monarchy: Monarch if (tokenStore.getLastToken() == null) { Timber.v("[PushRules] <-- No push rule check on initial sync") return - } //nothing on initial sync + } // nothing on initial sync val rules = pushRuleService.getPushRules(RuleScope.GLOBAL) processForPushTask.configureWith(ProcessEventForPushTask.Params(roomsSyncResponse, rules)) @@ -91,7 +92,6 @@ internal class RoomSyncHandler @Inject constructor(private val monarchy: Monarch // PRIVATE METHODS ***************************************************************************** private fun handleRoomSync(realm: Realm, handlingStrategy: HandlingStrategy, isInitialSync: Boolean, reporter: DefaultInitialSyncProgressService?) { - val rooms = when (handlingStrategy) { is HandlingStrategy.JOINED -> handlingStrategy.data.mapWithProgress(reporter, R.string.initial_sync_start_importing_account_joined_rooms, 0.6f) { @@ -115,7 +115,6 @@ internal class RoomSyncHandler @Inject constructor(private val monarchy: Monarch roomId: String, roomSync: RoomSync, isInitialSync: Boolean): RoomEntity { - Timber.v("Handle join sync for room $roomId") if (roomSync.ephemeral != null && roomSync.ephemeral.events.isNotEmpty()) { @@ -135,7 +134,8 @@ internal class RoomSyncHandler @Inject constructor(private val monarchy: Monarch // State event if (roomSync.state != null && roomSync.state.events.isNotEmpty()) { - val minStateIndex = roomEntity.untimelinedStateEvents.where().min(EventEntityFields.STATE_INDEX)?.toInt() ?: Int.MIN_VALUE + val minStateIndex = roomEntity.untimelinedStateEvents.where().min(EventEntityFields.STATE_INDEX)?.toInt() + ?: Int.MIN_VALUE val untimelinedStateIndex = minStateIndex + 1 roomSync.state.events.forEach { event -> roomEntity.addStateEvent(event, filterDuplicates = true, stateIndex = untimelinedStateIndex) @@ -192,7 +192,6 @@ internal class RoomSyncHandler @Inject constructor(private val monarchy: Monarch eventList: List, prevToken: String? = null, isLimited: Boolean = true): ChunkEntity { - val lastChunk = ChunkEntity.findLastLiveChunkFromRoom(realm, roomEntity.roomId) var stateIndexOffset = 0 val chunkEntity = if (!isLimited && lastChunk != null) { @@ -230,25 +229,28 @@ internal class RoomSyncHandler @Inject constructor(private val monarchy: Monarch return chunkEntity } - @Suppress("UNCHECKED_CAST") private fun handleEphemeral(realm: Realm, roomId: String, ephemeral: RoomSyncEphemeral, - isInitalSync: Boolean) { + isInitialSync: Boolean) { for (event in ephemeral.events) { if (event.type != EventType.RECEIPT) continue val readReceiptContent = event.content as? ReadReceiptContent ?: continue - readReceiptHandler.handle(realm, roomId, readReceiptContent, isInitalSync) + readReceiptHandler.handle(realm, roomId, readReceiptContent, isInitialSync) } } private fun handleRoomAccountDataEvents(realm: Realm, roomId: String, accountData: RoomSyncAccountData) { - accountData.events - .asSequence() - .filter { it.getClearType() == EventType.TAG } - .map { it.content.toModel() } - .forEach { roomTagHandler.handle(realm, roomId, it) } + for (event in accountData.events) { + val eventType = event.getClearType() + if (eventType == EventType.TAG) { + val content = event.getClearContent().toModel() + roomTagHandler.handle(realm, roomId, content) + } else if (eventType == EventType.FULLY_READ) { + val content = event.getClearContent().toModel() + roomFullyReadHandler.handle(realm, roomId, content) + } + } } - } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/RoomTagHandler.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/RoomTagHandler.kt index 864bbce781..51e0e72ab9 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/RoomTagHandler.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/RoomTagHandler.kt @@ -39,5 +39,4 @@ internal class RoomTagHandler @Inject constructor() { roomSummaryEntity.tags.addAll(tags) realm.insertOrUpdate(roomSummaryEntity) } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncAPI.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncAPI.kt index 669f556c9c..237a6fa6fd 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncAPI.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncAPI.kt @@ -31,5 +31,4 @@ internal interface SyncAPI { @Headers("CONNECT_TIMEOUT:60000", "READ_TIMEOUT:60000", "WRITE_TIMEOUT:60000") @GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "sync") fun sync(@QueryMap params: Map): Call - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncModule.kt index 598d5f0717..c9081d1466 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncModule.kt @@ -37,5 +37,4 @@ internal abstract class SyncModule { @Binds abstract fun bindSyncTask(syncTask: DefaultSyncTask): SyncTask - } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncResponseHandler.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncResponseHandler.kt index 1b843bda19..1ae185b073 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncResponseHandler.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncResponseHandler.kt @@ -32,7 +32,7 @@ internal class SyncResponseHandler @Inject constructor(private val roomSyncHandl private val cryptoService: DefaultCryptoService, private val initialSyncProgressService: DefaultInitialSyncProgressService) { - suspend fun handleResponse(syncResponse: SyncResponse, fromToken: String?, isCatchingUp: Boolean) { + suspend fun handleResponse(syncResponse: SyncResponse, fromToken: String?) { val isInitialSync = fromToken == null Timber.v("Start handling sync, is InitialSync: $isInitialSync") val reporter = initialSyncProgressService.takeIf { isInitialSync } @@ -71,7 +71,6 @@ internal class SyncResponseHandler @Inject constructor(private val roomSyncHandl Timber.v("Finish handling rooms in $it ms") } - measureTimeMillis { reportSubtask(reporter, R.string.initial_sync_start_importing_account_groups, 100, 0.1f) { Timber.v("Handle groups") @@ -97,5 +96,4 @@ internal class SyncResponseHandler @Inject constructor(private val roomSyncHandl } Timber.v("Finish handling sync in $measure ms") } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncTask.kt index 28d4d5fc48..8a3bc1c046 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncTask.kt @@ -16,7 +16,6 @@ package im.vector.matrix.android.internal.session.sync -import com.zhuinden.monarchy.Monarchy import im.vector.matrix.android.R import im.vector.matrix.android.api.failure.Failure import im.vector.matrix.android.api.failure.MatrixError @@ -25,6 +24,7 @@ import im.vector.matrix.android.internal.di.UserId import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.session.DefaultInitialSyncProgressService import im.vector.matrix.android.internal.session.filter.FilterRepository +import im.vector.matrix.android.internal.session.homeserver.GetHomeServerCapabilitiesTask import im.vector.matrix.android.internal.session.sync.model.SyncResponse import im.vector.matrix.android.internal.task.Task import javax.inject.Inject @@ -32,7 +32,6 @@ import javax.inject.Inject internal interface SyncTask : Task { data class Params(var timeout: Long = 30_000L) - } internal class DefaultSyncTask @Inject constructor(private val syncAPI: SyncAPI, @@ -42,11 +41,13 @@ internal class DefaultSyncTask @Inject constructor(private val syncAPI: SyncAPI, private val sessionParamsStore: SessionParamsStore, private val initialSyncProgressService: DefaultInitialSyncProgressService, private val syncTokenStore: SyncTokenStore, - private val monarchy: Monarchy + private val getHomeServerCapabilitiesTask: GetHomeServerCapabilitiesTask ) : SyncTask { - override suspend fun execute(params: SyncTask.Params) { + // Maybe refresh the home server capabilities data we know + getHomeServerCapabilitiesTask.execute(Unit) + val requestParams = HashMap() var timeout = 0L val token = syncTokenStore.getLastToken() @@ -74,10 +75,10 @@ internal class DefaultSyncTask @Inject constructor(private val syncAPI: SyncAPI, } throw throwable } - syncResponseHandler.handleResponse(syncResponse, token, false) + syncResponseHandler.handleResponse(syncResponse, token) syncTokenStore.saveToken(syncResponse.nextBatch) if (isInitialSync) { initialSyncProgressService.endAll() } } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncTokenStore.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncTokenStore.kt index 8823f2e38a..f56ee3352f 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncTokenStore.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncTokenStore.kt @@ -39,6 +39,4 @@ internal class SyncTokenStore @Inject constructor(@SessionDatabase private val r } realm.close() } - - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/UserAccountDataSyncHandler.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/UserAccountDataSyncHandler.kt index 87b4c2d1c1..56b96b428d 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/UserAccountDataSyncHandler.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/UserAccountDataSyncHandler.kt @@ -34,6 +34,7 @@ import im.vector.matrix.android.internal.session.user.accountdata.DirectChatsHel import im.vector.matrix.android.internal.session.user.accountdata.UpdateUserAccountDataTask import im.vector.matrix.android.internal.task.TaskExecutor import im.vector.matrix.android.internal.task.configureWith +import im.vector.matrix.android.internal.util.awaitTransaction import io.realm.Realm import timber.log.Timber import javax.inject.Inject @@ -62,8 +63,8 @@ internal class UserAccountDataSyncHandler @Inject constructor(private val monarc savePushRulesTask.execute(SavePushRulesTask.Params(userAccountDataPushRules.content)) } - private fun handleDirectChatRooms(directMessages: UserAccountDataDirectMessages) { - monarchy.runTransactionSync { realm -> + private suspend fun handleDirectChatRooms(directMessages: UserAccountDataDirectMessages) { + monarchy.awaitTransaction { realm -> val oldDirectRooms = RoomSummaryEntity.getDirectRooms(realm) oldDirectRooms.forEach { it.isDirect = false @@ -113,4 +114,4 @@ internal class UserAccountDataSyncHandler @Inject constructor(private val monarc updateUserAccountDataTask.configureWith(updateUserAccountParams).executeBy(taskExecutor) } } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/job/SyncService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/job/SyncService.kt index b5d83607b2..4e57aa5be1 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/job/SyncService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/job/SyncService.kt @@ -31,7 +31,8 @@ import im.vector.matrix.android.internal.task.TaskThread import im.vector.matrix.android.internal.task.configureWith import timber.log.Timber import java.net.SocketTimeoutException -import java.util.* +import java.util.Timer +import java.util.TimerTask /** * Can execute periodic sync task. @@ -48,11 +49,10 @@ open class SyncService : Service() { private lateinit var networkConnectivityChecker: NetworkConnectivityChecker private lateinit var taskExecutor: TaskExecutor - var timer = Timer() override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { - Timber.i("onStartCommand ${intent}") + Timber.i("onStartCommand $intent") intent?.let { val userId = it.getStringExtra(EXTRA_USER_ID) val sessionComponent = Matrix.getInstance(applicationContext).sessionManager.getSessionComponent(userId) @@ -65,11 +65,11 @@ open class SyncService : Service() { timer = Timer() doSync(true) } else { - //Already syncing ignore + // Already syncing ignore Timber.i("Received a start while was already syncking... ignore") } } - //No intent just start the service, an alarm will should call with intent + // No intent just start the service, an alarm will should call with intent return START_STICKY } @@ -95,7 +95,7 @@ open class SyncService : Service() { fun doSync(once: Boolean = false) { if (!networkConnectivityChecker.hasInternetAccess) { Timber.v("No internet access. Waiting...") - //TODO Retry in ? + // TODO Retry in ? timer.schedule(object : TimerTask() { override fun run() { doSync() @@ -118,7 +118,7 @@ open class SyncService : Service() { } }, NEXT_BATCH_DELAY) } else { - //stop + // stop stopMe() } } @@ -169,5 +169,4 @@ open class SyncService : Service() { const val NEXT_BATCH_DELAY = 60_000L const val NO_NETWORK_DELAY = 5_000L } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/job/SyncThread.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/job/SyncThread.kt index f0b33809a1..d8de292d70 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/job/SyncThread.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/job/SyncThread.kt @@ -129,7 +129,6 @@ internal class SyncThread @Inject constructor(private val syncTask: SyncTask, this.callbackThread = TaskThread.SYNC this.executionThread = TaskThread.SYNC this.callback = object : MatrixCallback { - override fun onSuccess(data: Unit) { Timber.v("onSuccess") latch.countDown() @@ -184,7 +183,6 @@ internal class SyncThread @Inject constructor(private val syncTask: SyncTask, liveState.postValue(newState) } - override fun onMoveToForeground() { restart() } @@ -192,7 +190,4 @@ internal class SyncThread @Inject constructor(private val syncTask: SyncTask, override fun onMoveToBackground() { pause() } - } - - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/job/SyncWorker.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/job/SyncWorker.kt index b5d7118b81..b5177172d0 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/job/SyncWorker.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/job/SyncWorker.kt @@ -30,7 +30,6 @@ import timber.log.Timber import java.util.concurrent.TimeUnit import javax.inject.Inject - private const val DEFAULT_LONG_POOL_TIMEOUT = 0L internal class SyncWorker(context: Context, @@ -88,5 +87,4 @@ internal class SyncWorker(context: Context, WorkManager.getInstance(context).cancelUniqueWork("BG_SYNCP") } } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/DeviceInfo.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/DeviceInfo.kt index 0704c4236b..e91e2d0707 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/DeviceInfo.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/DeviceInfo.kt @@ -17,7 +17,6 @@ package im.vector.matrix.android.internal.session.sync.model import com.squareup.moshi.JsonClass - /** * This class describes the device information */ diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/DeviceListResponse.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/DeviceListResponse.kt index a6b2e4ab5d..9a7dd80572 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/DeviceListResponse.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/DeviceListResponse.kt @@ -27,4 +27,3 @@ internal data class DeviceListResponse( // List of user ids who are no more tracked. val left: List = emptyList() ) - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/DeviceOneTimeKeysCountSyncResponse.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/DeviceOneTimeKeysCountSyncResponse.kt index c1d9e0a13b..15df103e37 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/DeviceOneTimeKeysCountSyncResponse.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/DeviceOneTimeKeysCountSyncResponse.kt @@ -22,4 +22,4 @@ import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) internal data class DeviceOneTimeKeysCountSyncResponse( @Json(name = "signed_curve25519") val signedCurve25519: Int? = null -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/GroupSyncProfile.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/GroupSyncProfile.kt index 82c0b590bb..6d31e84d61 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/GroupSyncProfile.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/GroupSyncProfile.kt @@ -30,4 +30,4 @@ internal data class GroupSyncProfile( * The URL for the group's avatar. May be nil. */ @Json(name = "avatar_url") var avatarUrl: String? = null -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/GroupsSyncResponse.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/GroupsSyncResponse.kt index c296bd2ae8..c0a10c9667 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/GroupsSyncResponse.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/GroupsSyncResponse.kt @@ -35,4 +35,4 @@ internal data class GroupsSyncResponse( * Left groups. An array of groups ids: the groups that the user has left or been banned from. */ @Json(name = "leave") val leave: Map = emptyMap() -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/InvitedGroupSync.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/InvitedGroupSync.kt index fe61b4e440..128fcfad84 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/InvitedGroupSync.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/InvitedGroupSync.kt @@ -30,4 +30,4 @@ internal data class InvitedGroupSync( * The group profile. */ @Json(name = "profile") val profile: GroupSyncProfile? = null -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/InvitedRoomSync.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/InvitedRoomSync.kt index a5124e707e..9e39a323cd 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/InvitedRoomSync.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/InvitedRoomSync.kt @@ -30,4 +30,4 @@ internal data class InvitedRoomSync( * archived 'state' not the 'invite_state'. */ @Json(name = "invite_state") val inviteState: RoomInviteState? = null -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/PresenceSyncResponse.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/PresenceSyncResponse.kt index 71d997fe03..bbcb7badf0 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/PresenceSyncResponse.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/PresenceSyncResponse.kt @@ -27,4 +27,4 @@ internal data class PresenceSyncResponse( * List of presence events (array of Event with type m.presence). */ val events: List? = null -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/RoomInviteState.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/RoomInviteState.kt index 4fe6a31a9d..a9447caf06 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/RoomInviteState.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/RoomInviteState.kt @@ -15,7 +15,6 @@ */ package im.vector.matrix.android.internal.session.sync.model - import com.squareup.moshi.Json import com.squareup.moshi.JsonClass import im.vector.matrix.android.api.session.events.model.Event @@ -28,4 +27,4 @@ internal data class RoomInviteState( * List of state events (array of MXEvent). */ @Json(name = "events") val events: List = emptyList() -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/RoomResponse.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/RoomResponse.kt index aff709893f..453bd29c0b 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/RoomResponse.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/RoomResponse.kt @@ -16,7 +16,6 @@ package im.vector.matrix.android.internal.session.sync.model - import com.squareup.moshi.JsonClass import im.vector.matrix.android.api.session.events.model.Event diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/RoomSync.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/RoomSync.kt index ac36708374..2dd974f019 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/RoomSync.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/RoomSync.kt @@ -51,5 +51,4 @@ internal data class RoomSync( */ @Json(name = "summary") val summary: RoomSyncSummary? = null - -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/RoomSyncAccountData.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/RoomSyncAccountData.kt index 6c2e79f1b4..50bebc1713 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/RoomSyncAccountData.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/RoomSyncAccountData.kt @@ -26,4 +26,4 @@ internal data class RoomSyncAccountData( * List of account data events (array of Event). */ @Json(name = "events") val events: List = emptyList() -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/RoomSyncEphemeral.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/RoomSyncEphemeral.kt index 040c21fc6e..2342ce2e7f 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/RoomSyncEphemeral.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/RoomSyncEphemeral.kt @@ -16,7 +16,6 @@ package im.vector.matrix.android.internal.session.sync.model - import com.squareup.moshi.Json import com.squareup.moshi.JsonClass import im.vector.matrix.android.api.session.events.model.Event @@ -28,4 +27,4 @@ internal data class RoomSyncEphemeral( * List of ephemeral events (array of Event). */ @Json(name = "events") val events: List = emptyList() -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/RoomSyncState.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/RoomSyncState.kt index a760ef2e79..589cffa0e0 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/RoomSyncState.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/RoomSyncState.kt @@ -16,7 +16,6 @@ package im.vector.matrix.android.internal.session.sync.model - import com.squareup.moshi.Json import com.squareup.moshi.JsonClass import im.vector.matrix.android.api.session.events.model.Event diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/RoomSyncSummary.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/RoomSyncSummary.kt index 4a60a11c1f..c0f4eade70 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/RoomSyncSummary.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/RoomSyncSummary.kt @@ -19,7 +19,6 @@ package im.vector.matrix.android.internal.session.sync.model import com.squareup.moshi.Json import com.squareup.moshi.JsonClass - @JsonClass(generateAdapter = true) internal data class RoomSyncSummary( @@ -45,4 +44,4 @@ internal data class RoomSyncSummary( * The number of m.room.members in state 'invited' (can be null) */ @Json(name = "m.invited_member_count") val invitedMembersCount: Int? = null -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/RoomSyncTimeline.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/RoomSyncTimeline.kt index 886a30d259..cd22ea75cd 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/RoomSyncTimeline.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/RoomSyncTimeline.kt @@ -16,7 +16,6 @@ package im.vector.matrix.android.internal.session.sync.model - import com.squareup.moshi.Json import com.squareup.moshi.JsonClass import im.vector.matrix.android.api.session.events.model.Event @@ -39,4 +38,4 @@ internal data class RoomSyncTimeline( * If the batch was limited then this is a token that can be supplied to the server to retrieve more events */ @Json(name = "prev_batch") val prevToken: String? = null -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/RoomSyncUnreadNotifications.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/RoomSyncUnreadNotifications.kt index 5ec8f4b604..a29b893e82 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/RoomSyncUnreadNotifications.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/RoomSyncUnreadNotifications.kt @@ -16,7 +16,6 @@ package im.vector.matrix.android.internal.session.sync.model - import com.squareup.moshi.Json import com.squareup.moshi.JsonClass import im.vector.matrix.android.api.session.events.model.Event @@ -39,4 +38,4 @@ internal data class RoomSyncUnreadNotifications( /** * The number of highlighted unread messages (subset of notifications). */ - @Json(name = "highlight_count") val highlightCount: Int? = null) \ No newline at end of file + @Json(name = "highlight_count") val highlightCount: Int? = null) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/RoomsSyncResponse.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/RoomsSyncResponse.kt index 84ed6dfe50..9bd83ae25a 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/RoomsSyncResponse.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/RoomsSyncResponse.kt @@ -35,4 +35,4 @@ internal data class RoomsSyncResponse( * Left rooms. The rooms that the user has left or been banned from: keys are rooms ids. */ @Json(name = "leave") val leave: Map = emptyMap() -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/SyncResponse.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/SyncResponse.kt index dc05a45f80..d084dcdadd 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/SyncResponse.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/SyncResponse.kt @@ -58,11 +58,9 @@ internal data class SyncResponse( @Json(name = "device_one_time_keys_count") val deviceOneTimeKeysCount: DeviceOneTimeKeysCountSyncResponse? = null, - /** * List of groups. */ @Json(name = "groups") val groups: GroupsSyncResponse? = null - -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/ToDeviceSyncResponse.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/ToDeviceSyncResponse.kt index 86b685d367..382d2a804b 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/ToDeviceSyncResponse.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/ToDeviceSyncResponse.kt @@ -16,7 +16,6 @@ package im.vector.matrix.android.internal.session.sync.model - import com.squareup.moshi.JsonClass import im.vector.matrix.android.api.session.events.model.Event @@ -28,4 +27,4 @@ internal data class ToDeviceSyncResponse( * List of direct-to-device events. */ val events: List? = null -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/UserAccountData.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/UserAccountData.kt index 1362eb9171..2173d2f4df 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/UserAccountData.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/UserAccountData.kt @@ -25,4 +25,4 @@ internal interface UserAccountData { const val TYPE_WIDGETS = "m.widgets" const val TYPE_PUSH_RULES = "m.push_rules" } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/UserAccountDataDirectMessages.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/UserAccountDataDirectMessages.kt index 2ee1088d84..825a16cb1e 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/UserAccountDataDirectMessages.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/UserAccountDataDirectMessages.kt @@ -23,4 +23,3 @@ import com.squareup.moshi.JsonClass internal data class UserAccountDataDirectMessages( @Json(name = "content") val content: Map> ) : UserAccountData - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/UserAccountDataPushRules.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/UserAccountDataPushRules.kt index e2bd12f79b..7f357c876b 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/UserAccountDataPushRules.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/UserAccountDataPushRules.kt @@ -24,4 +24,3 @@ import im.vector.matrix.android.api.pushrules.rest.GetPushRulesResponse internal data class UserAccountDataPushRules( @Json(name = "content") val content: GetPushRulesResponse ) : UserAccountData - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/UserAccountDataSync.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/UserAccountDataSync.kt index 3d6131b3bf..4b9e9d652d 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/UserAccountDataSync.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/UserAccountDataSync.kt @@ -22,4 +22,4 @@ import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) internal data class UserAccountDataSync( @Json(name = "events") val list: List = emptyList() -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/DefaultUserService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/DefaultUserService.kt index 2925997347..be330bfc36 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/DefaultUserService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/DefaultUserService.kt @@ -26,7 +26,8 @@ import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.session.user.UserService import im.vector.matrix.android.api.session.user.model.User import im.vector.matrix.android.api.util.Cancelable -import im.vector.matrix.android.internal.database.RealmLiveData +import im.vector.matrix.android.api.util.Optional +import im.vector.matrix.android.api.util.toOptional import im.vector.matrix.android.internal.database.mapper.asDomain import im.vector.matrix.android.internal.database.model.UserEntity import im.vector.matrix.android.internal.database.model.UserEntityFields @@ -61,19 +62,18 @@ internal class DefaultUserService @Inject constructor(private val monarchy: Mona override fun getUser(userId: String): User? { val userEntity = monarchy.fetchCopied { UserEntity.where(it, userId).findFirst() } - ?: return null + ?: return null return userEntity.asDomain() } - override fun liveUser(userId: String): LiveData { - val liveRealmData = RealmLiveData(monarchy.realmConfiguration) { realm -> - UserEntity.where(realm, userId) - } - return Transformations.map(liveRealmData) { results -> - results - .map { it.asDomain() } - .firstOrNull() + override fun liveUser(userId: String): LiveData> { + val liveData = monarchy.findAllMappedWithChanges( + { UserEntity.where(it, userId) }, + { it.asDomain() } + ) + return Transformations.map(liveData) { results -> + results.firstOrNull().toOptional() } } @@ -106,7 +106,6 @@ internal class DefaultUserService @Inject constructor(private val monarchy: Mona return monarchy.findAllPagedWithChanges(realmDataSourceFactory, livePagedListBuilder) } - override fun searchUsersDirectory(search: String, limit: Int, excludedUserIds: Set, diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/SearchUserAPI.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/SearchUserAPI.kt index aa4d50df59..e57daed617 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/SearchUserAPI.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/SearchUserAPI.kt @@ -18,7 +18,7 @@ package im.vector.matrix.android.internal.session.user import im.vector.matrix.android.internal.network.NetworkConstants.URI_API_PREFIX_PATH_R0 import im.vector.matrix.android.internal.session.user.model.SearchUsersParams -import im.vector.matrix.android.internal.session.user.model.SearchUsersRequestResponse +import im.vector.matrix.android.internal.session.user.model.SearchUsersResponse import retrofit2.Call import retrofit2.http.Body import retrofit2.http.POST @@ -31,5 +31,5 @@ internal interface SearchUserAPI { * @param searchUsersParams the search params. */ @POST(URI_API_PREFIX_PATH_R0 + "user_directory/search") - fun searchUsers(@Body searchUsersParams: SearchUsersParams): Call -} \ No newline at end of file + fun searchUsers(@Body searchUsersParams: SearchUsersParams): Call +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/UserEntityFactory.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/UserEntityFactory.kt index 7873bf2f98..2ded32b7db 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/UserEntityFactory.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/UserEntityFactory.kt @@ -39,6 +39,4 @@ internal object UserEntityFactory { roomMember.avatarUrl ?: "" ) } - - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/UserModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/UserModule.kt index a31dc137c8..a997c616f3 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/UserModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/UserModule.kt @@ -43,5 +43,4 @@ internal abstract class UserModule { @Binds abstract fun bindSearchUserTask(searchUserTask: DefaultSearchUserTask): SearchUserTask - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/AccountDataModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/AccountDataModule.kt index 850312d8be..49fe8caf8e 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/AccountDataModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/AccountDataModule.kt @@ -32,10 +32,8 @@ internal abstract class AccountDataModule { fun providesAccountDataAPI(retrofit: Retrofit): AccountDataAPI { return retrofit.create(AccountDataAPI::class.java) } - } @Binds abstract fun bindUpdateUserAccountDataTask(updateUserAccountDataTask: DefaultUpdateUserAccountDataTask): UpdateUserAccountDataTask - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/DirectChatsHelper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/DirectChatsHelper.kt index b4b143878c..b5f404019a 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/DirectChatsHelper.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/DirectChatsHelper.kt @@ -31,20 +31,10 @@ internal class DirectChatsHelper @Inject constructor(@SessionDatabase */ fun getLocalUserAccount(filterRoomId: String? = null): MutableMap> { return Realm.getInstance(realmConfiguration).use { realm -> - val currentDirectRooms = RoomSummaryEntity.getDirectRooms(realm) - val directChatsMap = mutableMapOf>() - for (directRoom in currentDirectRooms) { - if (directRoom.roomId == filterRoomId) continue - val directUserId = directRoom.directUserId ?: continue - directChatsMap - .getOrPut(directUserId, { arrayListOf() }) - .apply { - add(directRoom.roomId) - } - } - directChatsMap + RoomSummaryEntity.getDirectRooms(realm) + .asSequence() + .filter { it.roomId != filterRoomId && it.directUserId != null } + .groupByTo(mutableMapOf(), { it.directUserId!! }, { it.roomId }) } } - - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/UpdateUserAccountDataTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/UpdateUserAccountDataTask.kt index aaa82efef0..5c0dac1125 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/UpdateUserAccountDataTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/UpdateUserAccountDataTask.kt @@ -37,8 +37,6 @@ internal interface UpdateUserAccountDataTask : Task> { internal class DefaultSearchUserTask @Inject constructor(private val searchUserAPI: SearchUserAPI) : SearchUserTask { override suspend fun execute(params: SearchUserTask.Params): List { - val response = executeRequest { + val response = executeRequest { apiCall = searchUserAPI.searchUsers(SearchUsersParams(params.search, params.limit)) } return response.users.map { User(it.userId, it.displayName, it.avatarUrl) } } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/model/SearchUsersResponse.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/model/SearchUsersResponse.kt index b0a8f93720..c324fdd8cf 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/model/SearchUsersResponse.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/model/SearchUsersResponse.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package im.vector.matrix.android.internal.session.user.model import com.squareup.moshi.Json @@ -7,8 +23,7 @@ import com.squareup.moshi.JsonClass * Class representing an users search response */ @JsonClass(generateAdapter = true) -internal data class SearchUsersRequestResponse( +internal data class SearchUsersResponse( @Json(name = "limited") val limited: Boolean = false, @Json(name = "results") val users: List = emptyList() ) - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/task/ConfigurableTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/task/ConfigurableTask.kt index 6896fe68b0..1bf939b91b 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/task/ConfigurableTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/task/ConfigurableTask.kt @@ -18,7 +18,7 @@ package im.vector.matrix.android.internal.task import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.util.Cancelable -import java.util.* +import java.util.UUID internal fun Task.configureWith(params: PARAMS, init: (ConfigurableTask.Builder.() -> Unit) = {} @@ -42,7 +42,6 @@ internal data class ConfigurableTask( ) : Task by task { - class Builder( private val task: Task, private val params: PARAMS, @@ -73,7 +72,4 @@ internal data class ConfigurableTask( override fun toString(): String { return "${task.javaClass.name} with ID: $id" } - } - - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/task/Task.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/task/Task.kt index be761fdbdc..de0f3dfbdd 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/task/Task.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/task/Task.kt @@ -19,6 +19,4 @@ package im.vector.matrix.android.internal.task internal interface Task { suspend fun execute(params: PARAMS): RESULT - } - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/task/TaskConstraints.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/task/TaskConstraints.kt index 18733d6ebf..d259576a11 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/task/TaskConstraints.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/task/TaskConstraints.kt @@ -19,4 +19,4 @@ package im.vector.matrix.android.internal.task data class TaskConstraints( val connectedToNetwork: Boolean = false -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/task/TaskExecutor.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/task/TaskExecutor.kt index c3f08b15ac..14e546e0d6 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/task/TaskExecutor.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/task/TaskExecutor.kt @@ -16,7 +16,6 @@ package im.vector.matrix.android.internal.task - import im.vector.matrix.android.api.util.Cancelable import im.vector.matrix.android.internal.di.MatrixScope import im.vector.matrix.android.internal.extensions.foldToCallback @@ -35,7 +34,6 @@ internal class TaskExecutor @Inject constructor(private val coroutineDispatchers private val executorScope = CoroutineScope(SupervisorJob()) fun execute(task: ConfigurableTask): Cancelable { - val job = executorScope.launch(task.callbackThread.toDispatcher()) { val resultOrFailure = runCatching { withContext(task.executionThread.toDispatcher()) { @@ -61,14 +59,12 @@ internal class TaskExecutor @Inject constructor(private val coroutineDispatchers fun cancelAll() = executorScope.coroutineContext.cancelChildren() - private suspend fun retry( times: Int = Int.MAX_VALUE, initialDelay: Long = 100, // 0.1 second maxDelay: Long = 10_000, // 10 second factor: Double = 2.0, block: suspend () -> T): T { - var currentDelay = initialDelay repeat(times - 1) { try { @@ -90,6 +86,4 @@ internal class TaskExecutor @Inject constructor(private val coroutineDispatchers TaskThread.CRYPTO -> coroutineDispatchers.crypto TaskThread.SYNC -> coroutineDispatchers.sync } - - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/task/TaskThread.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/task/TaskThread.kt index 659fd3dd9d..16ed93662c 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/task/TaskThread.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/task/TaskThread.kt @@ -23,4 +23,4 @@ internal enum class TaskThread { CALLER, CRYPTO, SYNC -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/BackgroundDetectionObserver.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/BackgroundDetectionObserver.kt index 9318b10717..d89b732a0d 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/BackgroundDetectionObserver.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/BackgroundDetectionObserver.kt @@ -61,5 +61,4 @@ internal class BackgroundDetectionObserver @Inject constructor() : LifecycleObse fun onMoveToForeground() fun onMoveToBackground() } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/CancelableCoroutine.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/CancelableCoroutine.kt index 97b8cd0e29..71e2d3fdb2 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/CancelableCoroutine.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/CancelableCoroutine.kt @@ -26,5 +26,4 @@ internal class CancelableCoroutine(private val job: Job) : Cancelable { job.cancel() } } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/CancelableWork.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/CancelableWork.kt index ddaeb1fd9d..bff20a80e7 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/CancelableWork.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/CancelableWork.kt @@ -27,5 +27,4 @@ internal class CancelableWork(private val context: Context, override fun cancel() { WorkManager.getInstance(context).cancelWorkById(workId) } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/CompatUtil.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/CompatUtil.kt index d0a5f2f82f..058a862bc8 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/CompatUtil.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/CompatUtil.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package im.vector.matrix.android.internal.util import android.content.Context @@ -34,7 +36,7 @@ import java.security.* import java.security.cert.CertificateException import java.security.spec.AlgorithmParameterSpec import java.security.spec.RSAKeyGenParameterSpec -import java.util.Calendar +import java.util.* import java.util.zip.GZIPOutputStream import javax.crypto.* import javax.crypto.spec.GCMParameterSpec @@ -57,19 +59,11 @@ object CompatUtil { private const val SHARED_KEY_ANDROID_VERSION_WHEN_KEY_HAS_BEEN_GENERATED = "android_version_when_key_has_been_generated" private var sSecretKeyAndVersion: SecretKeyAndVersion? = null - private var sPrng: SecureRandom? = null /** * Returns the unique SecureRandom instance shared for all local storage encryption operations. */ - private val prng: SecureRandom - get() { - if (sPrng == null) { - sPrng = SecureRandom() - } - - return sPrng!! - } + private val prng: SecureRandom by lazy(LazyThreadSafetyMode.NONE) { SecureRandom() } /** * Create a GZIPOutputStream instance @@ -238,15 +232,11 @@ object CompatUtil { KeyStoreException::class, IllegalBlockSizeException::class) fun createCipherOutputStream(out: OutputStream, context: Context): OutputStream? { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { return out } val keyAndVersion = getAesGcmLocalProtectionKey(context) - if (keyAndVersion == null || keyAndVersion.secretKey == null) { - throw KeyStoreException() - } val cipher = Cipher.getInstance(AES_GCM_CIPHER_TYPE) val iv: ByteArray @@ -261,7 +251,7 @@ object CompatUtil { } if (iv.size != AES_GCM_IV_LENGTH) { - Timber.e(TAG, "Invalid IV length " + iv.size) + Timber.e(TAG, "Invalid IV length ${iv.size}") return null } @@ -307,16 +297,11 @@ object CompatUtil { val cipher = Cipher.getInstance(AES_GCM_CIPHER_TYPE) val keyAndVersion = getAesGcmLocalProtectionKey(context) - if (keyAndVersion == null || keyAndVersion.secretKey == null) { - throw KeyStoreException() - } - val spec: AlgorithmParameterSpec - - if (keyAndVersion.androidVersionWhenTheKeyHasBeenGenerated >= Build.VERSION_CODES.M) { - spec = GCMParameterSpec(AES_GCM_KEY_SIZE_IN_BITS, iv) + val spec: AlgorithmParameterSpec = if (keyAndVersion.androidVersionWhenTheKeyHasBeenGenerated >= Build.VERSION_CODES.M) { + GCMParameterSpec(AES_GCM_KEY_SIZE_IN_BITS, iv) } else { - spec = IvParameterSpec(iv) + IvParameterSpec(iv) } cipher.init(Cipher.DECRYPT_MODE, keyAndVersion.secretKey, spec) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/Debouncer.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/Debouncer.kt index 8ecd72d90e..6a294d8d6c 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/Debouncer.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/Debouncer.kt @@ -40,4 +40,4 @@ internal class Debouncer(private val handler: Handler) { runnables[identifier] = chained handler.postDelayed(chained, millis) } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/FileSaver.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/FileSaver.kt index 4f695d2c74..562a32d7bb 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/FileSaver.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/FileSaver.kt @@ -17,7 +17,9 @@ package im.vector.matrix.android.internal.util import androidx.annotation.WorkerThread -import okio.Okio +import okio.buffer +import okio.sink +import okio.source import java.io.File import java.io.InputStream @@ -26,9 +28,9 @@ import java.io.InputStream */ @WorkerThread fun writeToFile(inputStream: InputStream, outputFile: File) { - Okio.buffer(Okio.source(inputStream)).use { input -> - Okio.buffer(Okio.sink(outputFile)).use { output -> + inputStream.source().buffer().use { input -> + outputFile.sink().buffer().use { output -> output.writeAll(input) } } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/Handler.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/Handler.kt index 51fdbfe227..5db1c46dd3 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/Handler.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/Handler.kt @@ -20,10 +20,10 @@ import android.os.Handler import android.os.HandlerThread import android.os.Looper -fun createBackgroundHandler(name: String): Handler = Handler( +internal fun createBackgroundHandler(name: String): Handler = Handler( HandlerThread(name).apply { start() }.looper ) -fun createUIHandler(): Handler = Handler( +internal fun createUIHandler(): Handler = Handler( Looper.getMainLooper() -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/Hash.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/Hash.kt index e57c289388..e748ad2778 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/Hash.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/Hash.kt @@ -24,12 +24,9 @@ import java.security.MessageDigest fun String.md5() = try { val digest = MessageDigest.getInstance("md5") digest.update(toByteArray()) - val bytes = digest.digest() - val sb = StringBuilder() - for (i in bytes.indices) { - sb.append(String.format("%02X", bytes[i])) - } - sb.toString().toLowerCase() + digest.digest() + .joinToString("") { String.format("%02X", it) } + .toLowerCase() } catch (exc: Exception) { // Should not happen, but just in case hashCode().toString() diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/JsonCanonicalizer.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/JsonCanonicalizer.kt index 1e7135e0de..e35dff5367 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/JsonCanonicalizer.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/JsonCanonicalizer.kt @@ -92,5 +92,4 @@ object JsonCanonicalizer { else -> return any.toString() } } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/LiveDataUtils.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/LiveDataUtils.kt index 952f12fde1..75fae162a5 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/LiveDataUtils.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/LiveDataUtils.kt @@ -24,7 +24,6 @@ object LiveDataUtils { fun combine(firstSource: LiveData, secondSource: LiveData, mapper: (FIRST, SECOND) -> OUT): LiveData { - return MediatorLiveData().apply { var firstValue: FIRST? = null var secondValue: SECOND? = null @@ -38,7 +37,6 @@ object LiveDataUtils { } } - addSource(firstSource) { firstValue = it valueDispatcher() @@ -50,5 +48,4 @@ object LiveDataUtils { } } } - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/MatrixCoroutineDispatchers.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/MatrixCoroutineDispatchers.kt index ef0c91a327..23201c084e 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/MatrixCoroutineDispatchers.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/MatrixCoroutineDispatchers.kt @@ -24,4 +24,4 @@ internal data class MatrixCoroutineDispatchers( val main: CoroutineDispatcher, val crypto: CoroutineDispatcher, val sync: CoroutineDispatcher -) \ No newline at end of file +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/StringProvider.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/StringProvider.kt index a90538656f..6cba29ceec 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/StringProvider.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/StringProvider.kt @@ -53,6 +53,4 @@ internal class StringProvider @Inject constructor(private val resources: Resourc fun getString(@StringRes resId: Int, vararg formatArgs: Any?): String { return resources.getString(resId, *formatArgs) } - - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/StringUtils.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/StringUtils.kt index a277498526..4a46a43f03 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/StringUtils.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/StringUtils.kt @@ -18,6 +18,7 @@ package im.vector.matrix.android.internal.util import im.vector.matrix.android.api.MatrixPatterns import timber.log.Timber +import java.util.* /** * Convert a string to an UTF8 String @@ -25,13 +26,13 @@ import timber.log.Timber * @param s the string to convert * @return the utf-8 string */ -fun convertToUTF8(s: String): String? { +fun convertToUTF8(s: String): String { return try { val bytes = s.toByteArray(Charsets.UTF_8) String(bytes) } catch (e: Exception) { Timber.e(e, "## convertToUTF8() failed") - null + s } } @@ -41,13 +42,13 @@ fun convertToUTF8(s: String): String? { * @param s the string to convert * @return the utf-16 string */ -fun convertFromUTF8(s: String): String? { +fun convertFromUTF8(s: String): String { return try { val bytes = s.toByteArray() String(bytes, Charsets.UTF_8) } catch (e: Exception) { Timber.e(e, "## convertFromUTF8() failed") - null + s } } @@ -55,5 +56,5 @@ fun String?.firstLetterOfDisplayName(): String { if (this.isNullOrEmpty()) return "" val isUserId = MatrixPatterns.isUserId(this) val firstLetterIndex = if (isUserId) 1 else 0 - return this[firstLetterIndex].toString().toUpperCase() -} \ No newline at end of file + return this[firstLetterIndex].toString().toUpperCase(Locale.ROOT) +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/SuspendMatrixCallback.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/SuspendMatrixCallback.kt index 801578ac86..e76137d0c2 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/SuspendMatrixCallback.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/SuspendMatrixCallback.kt @@ -32,4 +32,4 @@ suspend inline fun awaitCallback(crossinline callback: (MatrixCallback) - cont.resume(data) } }) -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/worker/AlwaysSuccessfulWorker.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/worker/AlwaysSuccessfulWorker.kt index c0cae10d8e..136e84d945 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/worker/AlwaysSuccessfulWorker.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/worker/AlwaysSuccessfulWorker.kt @@ -25,4 +25,4 @@ internal class AlwaysSuccessfulWorker(context: Context, params: WorkerParameters override fun doWork(): Result { return Result.success() } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/worker/DelegateWorkerFactory.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/worker/DelegateWorkerFactory.kt index fa38504935..2029596b0b 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/worker/DelegateWorkerFactory.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/worker/DelegateWorkerFactory.kt @@ -23,5 +23,4 @@ import androidx.work.WorkerParameters interface DelegateWorkerFactory { fun create(context: Context, params: WorkerParameters): ListenableWorker - -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/worker/WorkManagerUtil.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/worker/WorkManagerUtil.kt index 56516dbda0..27ec28dcac 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/worker/WorkManagerUtil.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/worker/WorkManagerUtil.kt @@ -46,4 +46,4 @@ internal object WorkManagerUtil { it.pruneWork() } } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/worker/Worker.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/worker/Worker.kt index 4a4b5e3b29..58abd10e81 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/worker/Worker.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/worker/Worker.kt @@ -22,4 +22,4 @@ import im.vector.matrix.android.internal.session.SessionComponent internal fun ListenableWorker.getSessionComponent(userId: String): SessionComponent? { return Matrix.getInstance(applicationContext).sessionManager.getSessionComponent(userId) -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/worker/WorkerParamsFactory.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/worker/WorkerParamsFactory.kt index 87d17b9cea..03a6d78c98 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/worker/WorkerParamsFactory.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/worker/WorkerParamsFactory.kt @@ -40,4 +40,4 @@ object WorkerParamsFactory { adapter.fromJson(json) } } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/res/values-de/strings.xml b/matrix-sdk-android/src/main/res/values-de/strings.xml index 3f37ec35f6..59b5ee4212 100644 --- a/matrix-sdk-android/src/main/res/values-de/strings.xml +++ b/matrix-sdk-android/src/main/res/values-de/strings.xml @@ -166,4 +166,14 @@ Sende eine Nachricht… Sendewarteschlange leeren + Erste Synchronisation: Importiere Benutzerkonto… + Erste Synchronisation: Importiere Cryptoschlüssel + Erste Synchronisation: Importiere Räume + Erste Synchronisation: Importiere betretene Räume + Erste Synchronisation: Importiere eingeladene Räume + Erste Synchronisation: Importiere verlassene Räume + Erste Synchronisation: Importiere Gemeinschaften + Erste Synchronisation: Importiere Benutzerdaten + + %1$s hat die Einladung an %2$s, den Raum zu betreten, zurückgezogen diff --git a/matrix-sdk-android/src/main/res/values-en-rUS/strings.xml b/matrix-sdk-android/src/main/res/values-en-rUS/strings.xml new file mode 100644 index 0000000000..09e9dfc111 --- /dev/null +++ b/matrix-sdk-android/src/main/res/values-en-rUS/strings.xml @@ -0,0 +1,11 @@ + + + + + + Wrench + Airplane + + + + diff --git a/matrix-sdk-android/src/main/res/values-eu/strings.xml b/matrix-sdk-android/src/main/res/values-eu/strings.xml index 25e0df10f4..5b36858253 100644 --- a/matrix-sdk-android/src/main/res/values-eu/strings.xml +++ b/matrix-sdk-android/src/main/res/values-eu/strings.xml @@ -172,4 +172,5 @@ Mezua bidaltzen… Garbitu bidalketa-ilara + %1$s erabiltzaileak %2$s gelara elkartzeko gonbidapena indargabetu du diff --git a/matrix-sdk-android/src/main/res/values-fi/strings.xml b/matrix-sdk-android/src/main/res/values-fi/strings.xml index 1cfc499380..3c02e5c2ce 100644 --- a/matrix-sdk-android/src/main/res/values-fi/strings.xml +++ b/matrix-sdk-android/src/main/res/values-fi/strings.xml @@ -22,7 +22,7 @@ %s soitti äänipuhelun. %s vastasi puheluun. %s lopetti puhelun. - %1$s muutti tulevan huonehistorian näkyväksi käyttäjälle %2$s + %1$s muutti tulevan huonehistorian näkyväksi seuraaville: %2$s kaikki huoneen jäsenet, kutsumisestaan asti. kaikki huoneen jäsenet, liittymisestään asti. kaikki huoneen jäsenet. @@ -34,7 +34,7 @@ VoIP-konferenssi alkoi VoIP-konferenssi päättyi - (myös profiilikuva vaihdettiin) + (myös kuva vaihdettiin) %1$s poisti huoneen nimen %1$s poisti huoneen aiheen %1$s päivitti profiilinsa %2$s @@ -173,4 +173,5 @@ Lähetetään viestiä… Tyhjennä lähetysjono + %1$s veti takaisin käyttäjän %2$s liittymiskutsun huoneeseen diff --git a/matrix-sdk-android/src/main/res/values-fr/strings.xml b/matrix-sdk-android/src/main/res/values-fr/strings.xml index 9541555d75..98a98a3e7a 100644 --- a/matrix-sdk-android/src/main/res/values-fr/strings.xml +++ b/matrix-sdk-android/src/main/res/values-fr/strings.xml @@ -172,4 +172,5 @@ Envoi du message… Vider la file d’envoi + %1$s a révoqué l’invitation pour %2$s à rejoindre le salon diff --git a/matrix-sdk-android/src/main/res/values-hu/strings.xml b/matrix-sdk-android/src/main/res/values-hu/strings.xml index e3d4e88c60..da6b8f5687 100644 --- a/matrix-sdk-android/src/main/res/values-hu/strings.xml +++ b/matrix-sdk-android/src/main/res/values-hu/strings.xml @@ -171,4 +171,5 @@ Üzenet küldése… Küldő sor ürítése + %1$s visszavonta a meghívót a belépéshez ebbe a szobába: %2$s diff --git a/matrix-sdk-android/src/main/res/values-it/strings.xml b/matrix-sdk-android/src/main/res/values-it/strings.xml index 1edc038175..a8d844ddde 100644 --- a/matrix-sdk-android/src/main/res/values-it/strings.xml +++ b/matrix-sdk-android/src/main/res/values-it/strings.xml @@ -172,4 +172,5 @@ Invio messaggio in corso … Cancella la coda di invio + %1$s ha revocato l\'invito a %2$s di unirsi alla stanza diff --git a/matrix-sdk-android/src/main/res/values-ko/strings.xml b/matrix-sdk-android/src/main/res/values-ko/strings.xml index 30145e31a3..959ff8a96e 100644 --- a/matrix-sdk-android/src/main/res/values-ko/strings.xml +++ b/matrix-sdk-android/src/main/res/values-ko/strings.xml @@ -26,12 +26,12 @@ %s님이 전화를 받았습니다. %s님이 전화를 끊었습니다. %1$s님이 이후 %2$s에게 방 기록을 공개했습니다 - 초대된 시점부터 모든 방 구성원. - 들어온 시점부터 모든 방 구성원. - 모든 방 구성원. + 초대된 시점부터 모든 방 구성원 + 들어온 시점부터 모든 방 구성원 + 모든 방 구성원 누구나. 알 수 없음 (%s). - %1$s님이 종단 간 암호화를 켰습니다 (%2$s) + %1$s님이 종단간 암호화를 켰습니다 (%2$s) %s님이 방을 업그레이드했습니다. %1$s님이 VoIP 회의를 요청했습니다 @@ -52,7 +52,7 @@ ** 암호를 해독할 수 없음: %s ** 발신인의 기기에서 이 메시지의 키를 보내지 않았습니다. - 이 답장의 질문 + 관련 대화 검열할 수 없습니다 메시지를 보낼 수 없습니다 @@ -170,4 +170,5 @@ 메시지 보내는 중… 전송 대기 열 지우기 + %1$s님이 %2$s님에게 방에 참가하라고 보낸 초대를 취소했습니다 diff --git a/matrix-sdk-android/src/main/res/values-nl/strings.xml b/matrix-sdk-android/src/main/res/values-nl/strings.xml index c2d524e486..6658f21583 100644 --- a/matrix-sdk-android/src/main/res/values-nl/strings.xml +++ b/matrix-sdk-android/src/main/res/values-nl/strings.xml @@ -181,4 +181,5 @@ Bericht wordt verstuurd… Uitgaande wachtrij legen + %1$s heeft de uitnodiging voor %2$s om het gesprek toe te treden ingetrokken diff --git a/matrix-sdk-android/src/main/res/values-ru/strings.xml b/matrix-sdk-android/src/main/res/values-ru/strings.xml index e0637ea671..07411c097f 100644 --- a/matrix-sdk-android/src/main/res/values-ru/strings.xml +++ b/matrix-sdk-android/src/main/res/values-ru/strings.xml @@ -185,4 +185,5 @@ Отправка сообщения… Очистить очередь отправки + %1$s отозвал приглашение %2$s присоединиться к комнате diff --git a/matrix-sdk-android/src/main/res/values-sq/strings.xml b/matrix-sdk-android/src/main/res/values-sq/strings.xml index 03d5df2b81..cffd55a7f7 100644 --- a/matrix-sdk-android/src/main/res/values-sq/strings.xml +++ b/matrix-sdk-android/src/main/res/values-sq/strings.xml @@ -168,4 +168,5 @@ Po dërgohet mesazh… Spastro radhë pritjeje + %1$s shfuqizoi ftesën për %2$s për pjesëmarrje te dhoma diff --git a/matrix-sdk-android/src/main/res/values-vls/strings.xml b/matrix-sdk-android/src/main/res/values-vls/strings.xml index eb533e15a0..dad88788e4 100644 --- a/matrix-sdk-android/src/main/res/values-vls/strings.xml +++ b/matrix-sdk-android/src/main/res/values-vls/strings.xml @@ -44,7 +44,7 @@ Bericht verwyderd [reden: %1$s] Bericht verwyderd deur %1$s [reden: %2$s] %1$s èt zyn/heur profiel %2$s bygewerkt - %1$s èt een uutnodigienge noa %2$s gesteurd vo ’t gesprek toe te treden + %1$s èt een uutnodigienge noa %2$s gesteurd vo ’t gesprek toe te treedn %1$s èt d’uutnodigienge vo %2$s anveird ** Kun nie ountsleuteln: %s ** @@ -172,4 +172,5 @@ Bericht wor verstuurd… Uutgoande wachtreeke leegn + %1$s èt d’uutnodigienge vo %2$s vo ’t gesprek toe te treedn ingetrokkn diff --git a/matrix-sdk-android/src/main/res/values-zh-rTW/strings.xml b/matrix-sdk-android/src/main/res/values-zh-rTW/strings.xml index e0e66a80a0..5b5ae3beb0 100644 --- a/matrix-sdk-android/src/main/res/values-zh-rTW/strings.xml +++ b/matrix-sdk-android/src/main/res/values-zh-rTW/strings.xml @@ -170,4 +170,5 @@ 正在傳送訊息…… 清除傳送佇列 + %1$s 撤銷了 %2$s 加入聊天室的邀請 diff --git a/matrix-sdk-android/src/main/res/values/strings.xml b/matrix-sdk-android/src/main/res/values/strings.xml index 40d359076c..604bb13a41 100644 --- a/matrix-sdk-android/src/main/res/values/strings.xml +++ b/matrix-sdk-android/src/main/res/values/strings.xml @@ -46,6 +46,7 @@ Message removed by %1$s [reason: %2$s] %1$s updated their profile %2$s %1$s sent an invitation to %2$s to join the room + %1$s revoked the invitation for %2$s to join the room %1$s accepted the invitation for %2$s ** Unable to decrypt: %s ** diff --git a/matrix-sdk-android/src/test/java/im/vector/matrix/android/api/pushrules/PushRuleActionsTest.kt b/matrix-sdk-android/src/test/java/im/vector/matrix/android/api/pushrules/PushRuleActionsTest.kt index 0de80ea436..f98af53333 100644 --- a/matrix-sdk-android/src/test/java/im/vector/matrix/android/api/pushrules/PushRuleActionsTest.kt +++ b/matrix-sdk-android/src/test/java/im/vector/matrix/android/api/pushrules/PushRuleActionsTest.kt @@ -21,7 +21,6 @@ import im.vector.matrix.android.internal.di.MoshiProvider import org.junit.Assert import org.junit.Test - class PushRuleActionsTest { @Test @@ -62,7 +61,6 @@ class PushRuleActionsTest { } """.trimIndent() - val pushRule = MoshiProvider.providesMoshi().adapter(PushRule::class.java).fromJson(rawPushRule) Assert.assertNotNull("Should have parsed the rule", pushRule) @@ -71,20 +69,16 @@ class PushRuleActionsTest { val actions = Action.mapFrom(pushRule) Assert.assertEquals(3, actions!!.size) - Assert.assertEquals("First action should be notify", Action.Type.NOTIFY, actions[0].type) - Assert.assertEquals("Second action should be tweak", Action.Type.SET_TWEAK, actions[1].type) Assert.assertEquals("Second action tweak key should be sound", "sound", actions[1].tweak_action) Assert.assertEquals("Second action should have default as stringValue", "default", actions[1].stringValue) Assert.assertNull("Second action boolValue should be null", actions[1].boolValue) - Assert.assertEquals("Third action should be tweak", Action.Type.SET_TWEAK, actions[2].type) Assert.assertEquals("Third action tweak key should be highlight", "highlight", actions[2].tweak_action) Assert.assertEquals("Third action tweak param should be false", false, actions[2].boolValue) Assert.assertNull("Third action stringValue should be null", actions[2].stringValue) - } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/test/java/im/vector/matrix/android/api/pushrules/PushrulesConditionTest.kt b/matrix-sdk-android/src/test/java/im/vector/matrix/android/api/pushrules/PushrulesConditionTest.kt index 47e1571e54..42e7e850b3 100644 --- a/matrix-sdk-android/src/test/java/im/vector/matrix/android/api/pushrules/PushrulesConditionTest.kt +++ b/matrix-sdk-android/src/test/java/im/vector/matrix/android/api/pushrules/PushrulesConditionTest.kt @@ -32,6 +32,7 @@ import im.vector.matrix.android.api.session.room.timeline.Timeline import im.vector.matrix.android.api.session.room.timeline.TimelineEvent import im.vector.matrix.android.api.session.room.timeline.TimelineSettings import im.vector.matrix.android.api.util.Cancelable +import im.vector.matrix.android.api.util.Optional import org.junit.Assert import org.junit.Test @@ -88,7 +89,6 @@ class PushrulesConditionTest { ).apply { assert(EventMatchCondition("content.membership", "invite").isSatisfied(this)) } - } @Test @@ -112,7 +112,6 @@ class PushrulesConditionTest { ).apply { assert(condition.isSatisfied(this)) } - } @Test @@ -128,11 +127,8 @@ class PushrulesConditionTest { assert(condition.isSatisfied(simpleTextEvent)) } - @Test fun test_roommember_condition() { - - val conditionEqual3 = RoomMemberCountCondition("3") val conditionEqual3Bis = RoomMemberCountCondition("==3") val conditionLessThan3 = RoomMemberCountCondition("<3") @@ -162,7 +158,6 @@ class PushrulesConditionTest { } } - @Test fun test_notice_condition() { val conditionEqual = EventMatchCondition("content.msgtype", "m.notice") @@ -177,15 +172,13 @@ class PushrulesConditionTest { } } - class MockRoomService() : RoomService { - override fun createRoom(createRoomParams: CreateRoomParams, callback: MatrixCallback): Cancelable { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + TODO("not implemented") // To change body of created functions use File | Settings | File Templates. } override fun joinRoom(roomId: String, viaServers: List, callback: MatrixCallback): Cancelable { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + TODO("not implemented") // To change body of created functions use File | Settings | File Templates. } override fun getRoom(roomId: String): Room? { @@ -199,178 +192,187 @@ class PushrulesConditionTest { override fun liveRoomSummaries(): LiveData> { return MutableLiveData() } + + override fun markAllAsRead(roomIds: List, callback: MatrixCallback): Cancelable { + TODO("not implemented") // To change body of created functions use File | Settings | File Templates. + } } class MockRoom(override val roomId: String, val _numberOfJoinedMembers: Int) : Room { + override fun getReadMarkerLive(): LiveData> { + TODO("not implemented") // To change body of created functions use File | Settings | File Templates. + } + + override fun getMyReadReceiptLive(): LiveData> { + TODO("not implemented") // To change body of created functions use File | Settings | File Templates. + } + override fun resendTextMessage(localEcho: TimelineEvent): Cancelable? { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + TODO("not implemented") // To change body of created functions use File | Settings | File Templates. } override fun resendMediaMessage(localEcho: TimelineEvent): Cancelable? { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + TODO("not implemented") // To change body of created functions use File | Settings | File Templates. } override fun deleteFailedEcho(localEcho: TimelineEvent) { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + TODO("not implemented") // To change body of created functions use File | Settings | File Templates. } override fun clearSendingQueue() { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + TODO("not implemented") // To change body of created functions use File | Settings | File Templates. } override fun resendAllFailedMessages() { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + TODO("not implemented") // To change body of created functions use File | Settings | File Templates. } override fun saveDraft(draft: UserDraft) { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + TODO("not implemented") // To change body of created functions use File | Settings | File Templates. } override fun deleteDraft() { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + TODO("not implemented") // To change body of created functions use File | Settings | File Templates. } override fun getDraftsLive(): LiveData> { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + TODO("not implemented") // To change body of created functions use File | Settings | File Templates. } override fun getEventReadReceiptsLive(eventId: String): LiveData> { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + TODO("not implemented") // To change body of created functions use File | Settings | File Templates. } override fun getStateEvent(eventType: String): Event? { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + TODO("not implemented") // To change body of created functions use File | Settings | File Templates. } override fun editReply(replyToEdit: TimelineEvent, originalTimelineEvent: TimelineEvent, newBodyText: String, compatibilityBodyText: String): Cancelable { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + TODO("not implemented") // To change body of created functions use File | Settings | File Templates. } override fun fetchEditHistory(eventId: String, callback: MatrixCallback>) { } - override fun liveTimeLineEvent(eventId: String): LiveData { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + override fun getTimeLineEventLive(eventId: String): LiveData> { + TODO("not implemented") // To change body of created functions use File | Settings | File Templates. } - override fun getNumberOfJoinedMembers(): Int { return _numberOfJoinedMembers } - override fun liveRoomSummary(): LiveData { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + override fun getRoomSummaryLive(): LiveData> { + TODO("not implemented") // To change body of created functions use File | Settings | File Templates. } override fun roomSummary(): RoomSummary? { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + TODO("not implemented") // To change body of created functions use File | Settings | File Templates. } override fun createTimeline(eventId: String?, settings: TimelineSettings): Timeline { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + TODO("not implemented") // To change body of created functions use File | Settings | File Templates. } override fun getTimeLineEvent(eventId: String): TimelineEvent? { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + TODO("not implemented") // To change body of created functions use File | Settings | File Templates. } override fun sendTextMessage(text: String, msgType: String, autoMarkdown: Boolean): Cancelable { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + TODO("not implemented") // To change body of created functions use File | Settings | File Templates. } override fun sendFormattedTextMessage(text: String, formattedText: String): Cancelable { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + TODO("not implemented") // To change body of created functions use File | Settings | File Templates. } override fun sendMedia(attachment: ContentAttachmentData): Cancelable { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + TODO("not implemented") // To change body of created functions use File | Settings | File Templates. } override fun sendMedias(attachments: List): Cancelable { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + TODO("not implemented") // To change body of created functions use File | Settings | File Templates. } override fun redactEvent(event: Event, reason: String?): Cancelable { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + TODO("not implemented") // To change body of created functions use File | Settings | File Templates. } override fun markAllAsRead(callback: MatrixCallback) { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + TODO("not implemented") // To change body of created functions use File | Settings | File Templates. } override fun setReadReceipt(eventId: String, callback: MatrixCallback) { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + TODO("not implemented") // To change body of created functions use File | Settings | File Templates. } override fun setReadMarker(fullyReadEventId: String, callback: MatrixCallback) { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + TODO("not implemented") // To change body of created functions use File | Settings | File Templates. } override fun isEventRead(eventId: String): Boolean { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + TODO("not implemented") // To change body of created functions use File | Settings | File Templates. } override fun loadRoomMembersIfNeeded(matrixCallback: MatrixCallback): Cancelable { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + TODO("not implemented") // To change body of created functions use File | Settings | File Templates. } override fun getRoomMember(userId: String): RoomMember? { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + TODO("not implemented") // To change body of created functions use File | Settings | File Templates. } override fun getRoomMemberIdsLive(): LiveData> { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + TODO("not implemented") // To change body of created functions use File | Settings | File Templates. } override fun invite(userId: String, callback: MatrixCallback): Cancelable { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + TODO("not implemented") // To change body of created functions use File | Settings | File Templates. } override fun join(viaServers: List, callback: MatrixCallback): Cancelable { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + TODO("not implemented") // To change body of created functions use File | Settings | File Templates. } override fun leave(callback: MatrixCallback): Cancelable { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + TODO("not implemented") // To change body of created functions use File | Settings | File Templates. } override fun updateTopic(topic: String, callback: MatrixCallback) { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + TODO("not implemented") // To change body of created functions use File | Settings | File Templates. } - override fun sendReaction(reaction: String, targetEventId: String): Cancelable { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + override fun sendReaction(targetEventId: String, reaction: String): Cancelable { + TODO("not implemented") // To change body of created functions use File | Settings | File Templates. } - override fun undoReaction(reaction: String, targetEventId: String, myUserId: String) { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + override fun undoReaction(targetEventId: String, reaction: String): Cancelable { + TODO("not implemented") // To change body of created functions use File | Settings | File Templates. } override fun editTextMessage(targetEventId: String, msgType: String, newBodyText: String, newBodyAutoMarkdown: Boolean, compatibilityBodyText: String): Cancelable { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + TODO("not implemented") // To change body of created functions use File | Settings | File Templates. } override fun replyToMessage(eventReplied: TimelineEvent, replyText: String, autoMarkdown: Boolean): Cancelable? { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + TODO("not implemented") // To change body of created functions use File | Settings | File Templates. } - override fun getEventSummaryLive(eventId: String): LiveData { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + override fun getEventSummaryLive(eventId: String): LiveData> { + TODO("not implemented") // To change body of created functions use File | Settings | File Templates. } override fun isEncrypted(): Boolean { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + TODO("not implemented") // To change body of created functions use File | Settings | File Templates. } override fun encryptionAlgorithm(): String? { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + TODO("not implemented") // To change body of created functions use File | Settings | File Templates. } override fun shouldEncryptForInvitedMembers(): Boolean { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + TODO("not implemented") // To change body of created functions use File | Settings | File Templates. } - } - } diff --git a/tools/check/forbidden_strings_in_code.txt b/tools/check/forbidden_strings_in_code.txt index 7686cb0b7c..36f26452f0 100644 --- a/tools/check/forbidden_strings_in_code.txt +++ b/tools/check/forbidden_strings_in_code.txt @@ -149,4 +149,13 @@ android\.app\.AlertDialog new Gson\(\) ### Use matrixOneTimeWorkRequestBuilder -import androidx.work.OneTimeWorkRequestBuilder===1 \ No newline at end of file +import androidx.work.OneTimeWorkRequestBuilder===1 + +### Use TextUtils.formatFileSize +Formatter\.formatFileSize===1 + +### Use TextUtils.formatFileSize with short format param to true +Formatter\.formatShortFileSize===1 + +### Use kotlin stdlib to test or compare strings +android\.text\.TextUtils diff --git a/tools/import_from_riot.sh b/tools/import_from_riot.sh index cdc4275095..2e4b332a3c 100755 --- a/tools/import_from_riot.sh +++ b/tools/import_from_riot.sh @@ -32,6 +32,7 @@ cp ../matrix-android-sdk/matrix-sdk/src/main/res/values-da/strings.xml ./mat cp ../matrix-android-sdk/matrix-sdk/src/main/res/values-de/strings.xml ./matrix-sdk-android/src/main/res/values-de/strings.xml cp ../matrix-android-sdk/matrix-sdk/src/main/res/values-el/strings.xml ./matrix-sdk-android/src/main/res/values-el/strings.xml cp ../matrix-android-sdk/matrix-sdk/src/main/res/values-eo/strings.xml ./matrix-sdk-android/src/main/res/values-eo/strings.xml +cp ../matrix-android-sdk/matrix-sdk/src/main/res/values-en-rUS/strings.xml ./matrix-sdk-android/src/main/res/values-en-rUS/strings.xml cp ../matrix-android-sdk/matrix-sdk/src/main/res/values-es/strings.xml ./matrix-sdk-android/src/main/res/values-es/strings.xml cp ../matrix-android-sdk/matrix-sdk/src/main/res/values-es-rMX/strings.xml ./matrix-sdk-android/src/main/res/values-es-rMX/strings.xml cp ../matrix-android-sdk/matrix-sdk/src/main/res/values-eu/strings.xml ./matrix-sdk-android/src/main/res/values-eu/strings.xml @@ -64,50 +65,51 @@ cp ../matrix-android-sdk/matrix-sdk/src/main/res/values-zh-rTW/strings.xml ./mat echo echo "Copy strings to RiotX" -cp ../riot-android/vector/src/main/res/values/strings.xml ./vector/src/main/res/values/strings.xml -cp ../riot-android/vector/src/main/res/values-ar/strings.xml ./vector/src/main/res/values-ar/strings.xml -cp ../riot-android/vector/src/main/res/values-bg/strings.xml ./vector/src/main/res/values-bg/strings.xml -cp ../riot-android/vector/src/main/res/values-bn-rIN/strings.xml ./vector/src/main/res/values-bn-rIN/strings.xml -cp ../riot-android/vector/src/main/res/values-bs/strings.xml ./vector/src/main/res/values-bs/strings.xml -cp ../riot-android/vector/src/main/res/values-ca/strings.xml ./vector/src/main/res/values-ca/strings.xml -cp ../riot-android/vector/src/main/res/values-cs/strings.xml ./vector/src/main/res/values-cs/strings.xml -cp ../riot-android/vector/src/main/res/values-da/strings.xml ./vector/src/main/res/values-da/strings.xml -cp ../riot-android/vector/src/main/res/values-de/strings.xml ./vector/src/main/res/values-de/strings.xml -cp ../riot-android/vector/src/main/res/values-el/strings.xml ./vector/src/main/res/values-el/strings.xml -cp ../riot-android/vector/src/main/res/values-eo/strings.xml ./vector/src/main/res/values-eo/strings.xml -cp ../riot-android/vector/src/main/res/values-es/strings.xml ./vector/src/main/res/values-es/strings.xml -cp ../riot-android/vector/src/main/res/values-es-rMX/strings.xml ./vector/src/main/res/values-es-rMX/strings.xml -cp ../riot-android/vector/src/main/res/values-eu/strings.xml ./vector/src/main/res/values-eu/strings.xml -cp ../riot-android/vector/src/main/res/values-fa/strings.xml ./vector/src/main/res/values-fa/strings.xml -cp ../riot-android/vector/src/main/res/values-fi/strings.xml ./vector/src/main/res/values-fi/strings.xml -cp ../riot-android/vector/src/main/res/values-fr/strings.xml ./vector/src/main/res/values-fr/strings.xml -cp ../riot-android/vector/src/main/res/values-fr-rCA/strings.xml ./vector/src/main/res/values-fr-rCA/strings.xml -cp ../riot-android/vector/src/main/res/values-gl/strings.xml ./vector/src/main/res/values-gl/strings.xml -cp ../riot-android/vector/src/main/res/values-hu/strings.xml ./vector/src/main/res/values-hu/strings.xml -cp ../riot-android/vector/src/main/res/values-id/strings.xml ./vector/src/main/res/values-id/strings.xml -cp ../riot-android/vector/src/main/res/values-in/strings.xml ./vector/src/main/res/values-in/strings.xml -cp ../riot-android/vector/src/main/res/values-is/strings.xml ./vector/src/main/res/values-is/strings.xml -cp ../riot-android/vector/src/main/res/values-it/strings.xml ./vector/src/main/res/values-it/strings.xml -cp ../riot-android/vector/src/main/res/values-ja/strings.xml ./vector/src/main/res/values-ja/strings.xml -cp ../riot-android/vector/src/main/res/values-ko/strings.xml ./vector/src/main/res/values-ko/strings.xml -cp ../riot-android/vector/src/main/res/values-lv/strings.xml ./vector/src/main/res/values-lv/strings.xml -cp ../riot-android/vector/src/main/res/values-nl/strings.xml ./vector/src/main/res/values-nl/strings.xml -cp ../riot-android/vector/src/main/res/values-nn/strings.xml ./vector/src/main/res/values-nn/strings.xml -cp ../riot-android/vector/src/main/res/values-pl/strings.xml ./vector/src/main/res/values-pl/strings.xml -cp ../riot-android/vector/src/main/res/values-pt/strings.xml ./vector/src/main/res/values-pt/strings.xml -cp ../riot-android/vector/src/main/res/values-pt-rBR/strings.xml ./vector/src/main/res/values-pt-rBR/strings.xml -cp ../riot-android/vector/src/main/res/values-ro/strings.xml ./vector/src/main/res/values-ro/strings.xml -cp ../riot-android/vector/src/main/res/values-ru/strings.xml ./vector/src/main/res/values-ru/strings.xml -cp ../riot-android/vector/src/main/res/values-sk/strings.xml ./vector/src/main/res/values-sk/strings.xml -cp ../riot-android/vector/src/main/res/values-sq/strings.xml ./vector/src/main/res/values-sq/strings.xml -cp ../riot-android/vector/src/main/res/values-te/strings.xml ./vector/src/main/res/values-te/strings.xml -cp ../riot-android/vector/src/main/res/values-th/strings.xml ./vector/src/main/res/values-th/strings.xml -cp ../riot-android/vector/src/main/res/values-tlh/strings.xml ./vector/src/main/res/values-tlh/strings.xml -cp ../riot-android/vector/src/main/res/values-tr/strings.xml ./vector/src/main/res/values-tr/strings.xml -cp ../riot-android/vector/src/main/res/values-uk/strings.xml ./vector/src/main/res/values-uk/strings.xml -cp ../riot-android/vector/src/main/res/values-vls/strings.xml ./vector/src/main/res/values-vls/strings.xml -cp ../riot-android/vector/src/main/res/values-zh-rCN/strings.xml ./vector/src/main/res/values-zh-rCN/strings.xml -cp ../riot-android/vector/src/main/res/values-zh-rTW/strings.xml ./vector/src/main/res/values-zh-rTW/strings.xml +cp ../riot-android/vector/src/main/res/values/strings.xml ./vector/src/main/res/values/strings.xml +cp ../riot-android/vector/src/main/res/values-ar/strings.xml ./vector/src/main/res/values-ar/strings.xml +cp ../riot-android/vector/src/main/res/values-b+sr+Latn/strings.xml ./vector/src/main/res/values-b+sr+Latn/strings.xml +cp ../riot-android/vector/src/main/res/values-bg/strings.xml ./vector/src/main/res/values-bg/strings.xml +cp ../riot-android/vector/src/main/res/values-bn-rIN/strings.xml ./vector/src/main/res/values-bn-rIN/strings.xml +cp ../riot-android/vector/src/main/res/values-bs/strings.xml ./vector/src/main/res/values-bs/strings.xml +cp ../riot-android/vector/src/main/res/values-ca/strings.xml ./vector/src/main/res/values-ca/strings.xml +cp ../riot-android/vector/src/main/res/values-cs/strings.xml ./vector/src/main/res/values-cs/strings.xml +cp ../riot-android/vector/src/main/res/values-da/strings.xml ./vector/src/main/res/values-da/strings.xml +cp ../riot-android/vector/src/main/res/values-de/strings.xml ./vector/src/main/res/values-de/strings.xml +cp ../riot-android/vector/src/main/res/values-el/strings.xml ./vector/src/main/res/values-el/strings.xml +cp ../riot-android/vector/src/main/res/values-eo/strings.xml ./vector/src/main/res/values-eo/strings.xml +cp ../riot-android/vector/src/main/res/values-es/strings.xml ./vector/src/main/res/values-es/strings.xml +cp ../riot-android/vector/src/main/res/values-es-rMX/strings.xml ./vector/src/main/res/values-es-rMX/strings.xml +cp ../riot-android/vector/src/main/res/values-eu/strings.xml ./vector/src/main/res/values-eu/strings.xml +cp ../riot-android/vector/src/main/res/values-fa/strings.xml ./vector/src/main/res/values-fa/strings.xml +cp ../riot-android/vector/src/main/res/values-fi/strings.xml ./vector/src/main/res/values-fi/strings.xml +cp ../riot-android/vector/src/main/res/values-fr/strings.xml ./vector/src/main/res/values-fr/strings.xml +cp ../riot-android/vector/src/main/res/values-fr-rCA/strings.xml ./vector/src/main/res/values-fr-rCA/strings.xml +cp ../riot-android/vector/src/main/res/values-gl/strings.xml ./vector/src/main/res/values-gl/strings.xml +cp ../riot-android/vector/src/main/res/values-hu/strings.xml ./vector/src/main/res/values-hu/strings.xml +cp ../riot-android/vector/src/main/res/values-id/strings.xml ./vector/src/main/res/values-id/strings.xml +cp ../riot-android/vector/src/main/res/values-in/strings.xml ./vector/src/main/res/values-in/strings.xml +cp ../riot-android/vector/src/main/res/values-is/strings.xml ./vector/src/main/res/values-is/strings.xml +cp ../riot-android/vector/src/main/res/values-it/strings.xml ./vector/src/main/res/values-it/strings.xml +cp ../riot-android/vector/src/main/res/values-ja/strings.xml ./vector/src/main/res/values-ja/strings.xml +cp ../riot-android/vector/src/main/res/values-ko/strings.xml ./vector/src/main/res/values-ko/strings.xml +cp ../riot-android/vector/src/main/res/values-lv/strings.xml ./vector/src/main/res/values-lv/strings.xml +cp ../riot-android/vector/src/main/res/values-nl/strings.xml ./vector/src/main/res/values-nl/strings.xml +cp ../riot-android/vector/src/main/res/values-nn/strings.xml ./vector/src/main/res/values-nn/strings.xml +cp ../riot-android/vector/src/main/res/values-pl/strings.xml ./vector/src/main/res/values-pl/strings.xml +cp ../riot-android/vector/src/main/res/values-pt/strings.xml ./vector/src/main/res/values-pt/strings.xml +cp ../riot-android/vector/src/main/res/values-pt-rBR/strings.xml ./vector/src/main/res/values-pt-rBR/strings.xml +cp ../riot-android/vector/src/main/res/values-ro/strings.xml ./vector/src/main/res/values-ro/strings.xml +cp ../riot-android/vector/src/main/res/values-ru/strings.xml ./vector/src/main/res/values-ru/strings.xml +cp ../riot-android/vector/src/main/res/values-sk/strings.xml ./vector/src/main/res/values-sk/strings.xml +cp ../riot-android/vector/src/main/res/values-sq/strings.xml ./vector/src/main/res/values-sq/strings.xml +cp ../riot-android/vector/src/main/res/values-te/strings.xml ./vector/src/main/res/values-te/strings.xml +cp ../riot-android/vector/src/main/res/values-th/strings.xml ./vector/src/main/res/values-th/strings.xml +cp ../riot-android/vector/src/main/res/values-tlh/strings.xml ./vector/src/main/res/values-tlh/strings.xml +cp ../riot-android/vector/src/main/res/values-tr/strings.xml ./vector/src/main/res/values-tr/strings.xml +cp ../riot-android/vector/src/main/res/values-uk/strings.xml ./vector/src/main/res/values-uk/strings.xml +cp ../riot-android/vector/src/main/res/values-vls/strings.xml ./vector/src/main/res/values-vls/strings.xml +cp ../riot-android/vector/src/main/res/values-zh-rCN/strings.xml ./vector/src/main/res/values-zh-rCN/strings.xml +cp ../riot-android/vector/src/main/res/values-zh-rTW/strings.xml ./vector/src/main/res/values-zh-rTW/strings.xml echo echo "Success!" diff --git a/vector/build.gradle b/vector/build.gradle index 1364093ddb..3ef125d331 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -15,8 +15,8 @@ androidExtensions { } ext.versionMajor = 0 -ext.versionMinor = 6 -ext.versionPatch = 1 +ext.versionMinor = 7 +ext.versionPatch = 0 static def getGitTimestamp() { def cmd = 'git show -s --format=%ct' @@ -208,18 +208,22 @@ android { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } + + kotlinOptions { + jvmTarget = "1.8" + } } dependencies { - def epoxy_version = "3.7.0" + def epoxy_version = '3.8.0' def arrow_version = "0.8.2" - def coroutines_version = "1.0.1" - def markwon_version = '3.0.0' + def coroutines_version = "1.3.2" + def markwon_version = '3.1.0' def big_image_viewer_version = '1.5.6' - def glide_version = '4.9.0' + def glide_version = '4.10.0' def moshi_version = '1.8.0' - def daggerVersion = '2.23.1' + def daggerVersion = '2.24' implementation project(":matrix-sdk-android") implementation project(":matrix-sdk-android-rx") @@ -229,12 +233,14 @@ dependencies { implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version" - implementation 'androidx.appcompat:appcompat:1.1.0-beta01' + implementation 'androidx.appcompat:appcompat:1.1.0' //Do not use beta2 at the moment, as it breaks things implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta1' - implementation 'androidx.core:core-ktx:1.0.2' + implementation 'androidx.core:core-ktx:1.1.0' + + implementation "org.threeten:threetenbp:1.4.0:no-tzdb" + implementation "com.gabrielittner.threetenbp:lazythreetenbp:0.7.0" - implementation 'com.jakewharton.threetenabp:threetenabp:1.1.1' implementation "com.squareup.moshi:moshi-adapters:$moshi_version" kapt "com.squareup.moshi:moshi-kotlin-codegen:$moshi_version" @@ -245,12 +251,12 @@ dependencies { implementation 'com.jakewharton.timber:timber:4.7.1' // Debug - implementation 'com.facebook.stetho:stetho:1.5.0' + implementation 'com.facebook.stetho:stetho:1.5.1' // rx implementation 'io.reactivex.rxjava2:rxkotlin:2.3.0' - implementation 'io.reactivex.rxjava2:rxandroid:2.1.0' - implementation 'com.jakewharton.rxrelay2:rxrelay:2.1.0' + implementation 'io.reactivex.rxjava2:rxandroid:2.1.1' + implementation 'com.jakewharton.rxrelay2:rxrelay:2.1.1' // RXBinding implementation 'com.jakewharton.rxbinding3:rxbinding:3.0.0' implementation 'com.jakewharton.rxbinding3:rxbinding-appcompat:3.0.0' @@ -259,10 +265,10 @@ dependencies { implementation("com.airbnb.android:epoxy:$epoxy_version") kapt "com.airbnb.android:epoxy-processor:$epoxy_version" implementation "com.airbnb.android:epoxy-paging:$epoxy_version" - implementation 'com.airbnb.android:mvrx:1.0.1' + implementation 'com.airbnb.android:mvrx:1.1.0' // Work - implementation "androidx.work:work-runtime-ktx:2.1.0-rc01" + implementation "androidx.work:work-runtime-ktx:2.3.0-alpha01" // Paging implementation "androidx.paging:paging-runtime-ktx:2.1.0" @@ -271,21 +277,19 @@ dependencies { implementation "io.arrow-kt:arrow-core:$arrow_version" // Pref - implementation 'androidx.preference:preference:1.0.0' + implementation 'androidx.preference:preference:1.1.0' // UI implementation 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1' - implementation 'com.google.android.material:material:1.1.0-alpha08' + implementation 'com.google.android.material:material:1.1.0-beta01' implementation 'me.gujun.android:span:1.7' implementation "ru.noties.markwon:core:$markwon_version" implementation "ru.noties.markwon:html:$markwon_version" implementation 'me.saket:better-link-movement-method:2.2.0' - - // Bus - implementation 'org.greenrobot:eventbus:3.1.1' + implementation 'com.google.android:flexbox:1.1.1' // Passphrase strength helper - implementation 'com.nulab-inc:zxcvbn:1.2.5' + implementation 'com.nulab-inc:zxcvbn:1.2.7' //Alerter implementation 'com.tapadoo.android:alerter:4.0.3' @@ -293,8 +297,8 @@ dependencies { implementation 'com.otaliastudios:autocomplete:1.1.0' // Butterknife - implementation 'com.jakewharton:butterknife:10.1.0' - kapt 'com.jakewharton:butterknife-compiler:10.1.0' + implementation 'com.jakewharton:butterknife:10.2.0' + kapt 'com.jakewharton:butterknife-compiler:10.2.0' // Shake detection implementation 'com.squareup:seismic:1.0.2' @@ -309,19 +313,21 @@ dependencies { implementation 'com.danikula:videocache:2.7.1' // Badge for compatibility - implementation 'me.leolin:ShortcutBadger:1.1.2@aar' + implementation 'me.leolin:ShortcutBadger:1.1.22@aar' // File picker - implementation 'com.github.jaiselrahman:FilePicker:1.2.2' + implementation 'com.kbeanie:multipicker:1.6@aar' // DI implementation "com.google.dagger:dagger:$daggerVersion" kapt "com.google.dagger:dagger-compiler:$daggerVersion" - compileOnly 'com.squareup.inject:assisted-inject-annotations-dagger2:0.4.0' - kapt 'com.squareup.inject:assisted-inject-processor-dagger2:0.4.0' + compileOnly 'com.squareup.inject:assisted-inject-annotations-dagger2:0.5.0' + kapt 'com.squareup.inject:assisted-inject-processor-dagger2:0.5.0' // gplay flavor only - gplayImplementation('com.google.firebase:firebase-messaging:19.0.1') { + // Warning: due to the exclude, Android Studio does not propose to upgrade. Uncomment next line to be proposed to upgrade + // implementation 'com.google.firebase:firebase-messaging:20.0.0' + gplayImplementation('com.google.firebase:firebase-messaging:20.0.0') { exclude group: 'com.google.firebase', module: 'firebase-core' exclude group: 'com.google.firebase', module: 'firebase-analytics' exclude group: 'com.google.firebase', module: 'firebase-measurement-connector' diff --git a/vector/src/debug/java/im/vector/riotx/features/debug/DebugMaterialThemeActivity.kt b/vector/src/debug/java/im/vector/riotx/features/debug/DebugMaterialThemeActivity.kt index ab6b86801a..542b0a1cbb 100644 --- a/vector/src/debug/java/im/vector/riotx/features/debug/DebugMaterialThemeActivity.kt +++ b/vector/src/debug/java/im/vector/riotx/features/debug/DebugMaterialThemeActivity.kt @@ -59,7 +59,7 @@ abstract class DebugMaterialThemeActivity : AppCompatActivity() { } override fun onCreateOptionsMenu(menu: Menu): Boolean { - menuInflater.inflate(R.menu.vector_home, menu) + menuInflater.inflate(R.menu.home, menu) return true } } diff --git a/vector/src/debug/java/im/vector/riotx/features/debug/DebugMaterialThemeDarkActivity.kt b/vector/src/debug/java/im/vector/riotx/features/debug/DebugMaterialThemeDarkActivity.kt index 83c3266c00..f925c7b2c3 100644 --- a/vector/src/debug/java/im/vector/riotx/features/debug/DebugMaterialThemeDarkActivity.kt +++ b/vector/src/debug/java/im/vector/riotx/features/debug/DebugMaterialThemeDarkActivity.kt @@ -16,4 +16,4 @@ package im.vector.riotx.features.debug -class DebugMaterialThemeDarkActivity : DebugMaterialThemeActivity() \ No newline at end of file +class DebugMaterialThemeDarkActivity : DebugMaterialThemeActivity() diff --git a/vector/src/debug/java/im/vector/riotx/features/debug/DebugMaterialThemeLightActivity.kt b/vector/src/debug/java/im/vector/riotx/features/debug/DebugMaterialThemeLightActivity.kt index d7e6fd1f79..1602bb0553 100644 --- a/vector/src/debug/java/im/vector/riotx/features/debug/DebugMaterialThemeLightActivity.kt +++ b/vector/src/debug/java/im/vector/riotx/features/debug/DebugMaterialThemeLightActivity.kt @@ -16,4 +16,4 @@ package im.vector.riotx.features.debug -class DebugMaterialThemeLightActivity : DebugMaterialThemeActivity() \ No newline at end of file +class DebugMaterialThemeLightActivity : DebugMaterialThemeActivity() diff --git a/vector/src/debug/java/im/vector/riotx/features/debug/DebugMenuActivity.kt b/vector/src/debug/java/im/vector/riotx/features/debug/DebugMenuActivity.kt index 30b01aa9a5..bfb9f0654e 100644 --- a/vector/src/debug/java/im/vector/riotx/features/debug/DebugMenuActivity.kt +++ b/vector/src/debug/java/im/vector/riotx/features/debug/DebugMenuActivity.kt @@ -27,7 +27,6 @@ import butterknife.OnClick import im.vector.riotx.R import im.vector.riotx.core.platform.VectorBaseActivity - class DebugMenuActivity : VectorBaseActivity() { override fun getLayoutRes() = R.layout.activity_debug_menu @@ -64,7 +63,6 @@ class DebugMenuActivity : VectorBaseActivity() { (getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager).createNotificationChannel(channel2) } - val builder = NotificationCompat.Builder(this, "CHAN") .setWhen(System.currentTimeMillis()) .setContentTitle("Title") @@ -92,7 +90,6 @@ class DebugMenuActivity : VectorBaseActivity() { .addMessage("Message 2 - 1", System.currentTimeMillis(), Person.Builder().setName("user 1-1").build()) .addMessage("Message 2 - 2", System.currentTimeMillis(), Person.Builder().setName("user 1-2").build()) - notificationManager.notify(10, builder.build()) notificationManager.notify( @@ -137,6 +134,4 @@ class DebugMenuActivity : VectorBaseActivity() { fun testCrash() { throw RuntimeException("Application crashed from user demand") } - } - diff --git a/vector/src/debug/java/im/vector/riotx/features/debug/TestLinkifyActivity.kt b/vector/src/debug/java/im/vector/riotx/features/debug/TestLinkifyActivity.kt index b91f5db728..6af4317094 100644 --- a/vector/src/debug/java/im/vector/riotx/features/debug/TestLinkifyActivity.kt +++ b/vector/src/debug/java/im/vector/riotx/features/debug/TestLinkifyActivity.kt @@ -27,7 +27,6 @@ import butterknife.BindView import butterknife.ButterKnife import im.vector.riotx.R - class TestLinkifyActivity : AppCompatActivity() { @BindView(R.id.test_linkify_content_view) @@ -36,7 +35,6 @@ class TestLinkifyActivity : AppCompatActivity() { @BindView(R.id.test_linkify_coordinator) lateinit var coordinatorLayout: CoordinatorLayout - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_test_linkify) diff --git a/vector/src/fdroid/java/im/vector/riotx/fdroid/features/settings/troubleshoot/TestAutoStartBoot.kt b/vector/src/fdroid/java/im/vector/riotx/fdroid/features/settings/troubleshoot/TestAutoStartBoot.kt index fa4b8aa375..3cbd6699fd 100644 --- a/vector/src/fdroid/java/im/vector/riotx/fdroid/features/settings/troubleshoot/TestAutoStartBoot.kt +++ b/vector/src/fdroid/java/im/vector/riotx/fdroid/features/settings/troubleshoot/TestAutoStartBoot.kt @@ -44,4 +44,4 @@ class TestAutoStartBoot @Inject constructor(private val vectorPreferences: Vecto status = TestStatus.FAILED } } -} \ No newline at end of file +} diff --git a/vector/src/fdroid/java/im/vector/riotx/fdroid/features/settings/troubleshoot/TestBackgroundRestrictions.kt b/vector/src/fdroid/java/im/vector/riotx/fdroid/features/settings/troubleshoot/TestBackgroundRestrictions.kt index b0c40a5463..67ca2627bc 100644 --- a/vector/src/fdroid/java/im/vector/riotx/fdroid/features/settings/troubleshoot/TestBackgroundRestrictions.kt +++ b/vector/src/fdroid/java/im/vector/riotx/fdroid/features/settings/troubleshoot/TestBackgroundRestrictions.kt @@ -33,9 +33,8 @@ class TestBackgroundRestrictions @Inject constructor(private val context: AppCom // Checks if the device is on a metered network if (isActiveNetworkMetered) { // Checks user’s Data Saver settings. - val restrictBackgroundStatus = ConnectivityManagerCompat.getRestrictBackgroundStatus(this) - when (restrictBackgroundStatus) { - ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED -> { + when (ConnectivityManagerCompat.getRestrictBackgroundStatus(this)) { + ConnectivityManagerCompat.RESTRICT_BACKGROUND_STATUS_ENABLED -> { // Background data usage is blocked for this app. Wherever possible, // the app should also use less data in the foreground. description = stringProvider.getString(R.string.settings_troubleshoot_test_bg_restricted_failed, @@ -43,7 +42,7 @@ class TestBackgroundRestrictions @Inject constructor(private val context: AppCom status = TestStatus.FAILED quickFix = null } - ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED -> { + ConnectivityManagerCompat.RESTRICT_BACKGROUND_STATUS_WHITELISTED -> { // The app is whitelisted. Wherever possible, // the app should use less data in the foreground and background. description = stringProvider.getString(R.string.settings_troubleshoot_test_bg_restricted_success, @@ -51,7 +50,7 @@ class TestBackgroundRestrictions @Inject constructor(private val context: AppCom status = TestStatus.SUCCESS quickFix = null } - ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED -> { + ConnectivityManagerCompat.RESTRICT_BACKGROUND_STATUS_DISABLED -> { // Data Saver is disabled. Since the device is connected to a // metered network, the app should use less data wherever possible. description = stringProvider.getString(R.string.settings_troubleshoot_test_bg_restricted_success, @@ -59,9 +58,7 @@ class TestBackgroundRestrictions @Inject constructor(private val context: AppCom status = TestStatus.SUCCESS quickFix = null } - } - } else { // The device is not on a metered network. // Use data as required to perform syncs, downloads, and updates. @@ -71,5 +68,4 @@ class TestBackgroundRestrictions @Inject constructor(private val context: AppCom } } } - -} \ No newline at end of file +} diff --git a/vector/src/fdroid/java/im/vector/riotx/fdroid/features/settings/troubleshoot/TestBatteryOptimization.kt b/vector/src/fdroid/java/im/vector/riotx/fdroid/features/settings/troubleshoot/TestBatteryOptimization.kt index 041f392c46..4d18beac8f 100644 --- a/vector/src/fdroid/java/im/vector/riotx/fdroid/features/settings/troubleshoot/TestBatteryOptimization.kt +++ b/vector/src/fdroid/java/im/vector/riotx/fdroid/features/settings/troubleshoot/TestBatteryOptimization.kt @@ -26,7 +26,6 @@ import im.vector.riotx.features.settings.troubleshoot.TroubleshootTest class TestBatteryOptimization(val fragment: Fragment) : TroubleshootTest(R.string.settings_troubleshoot_test_battery_title) { override fun perform() { - if (fragment.context != null && isIgnoringBatteryOptimizations(fragment.context!!)) { description = fragment.getString(R.string.settings_troubleshoot_test_battery_success) status = TestStatus.SUCCESS @@ -43,5 +42,4 @@ class TestBatteryOptimization(val fragment: Fragment) : TroubleshootTest(R.strin status = TestStatus.FAILED } } - -} \ No newline at end of file +} diff --git a/vector/src/fdroid/java/im/vector/riotx/fdroid/package-info.kt b/vector/src/fdroid/java/im/vector/riotx/fdroid/package-info.kt index 7e0e112312..cd72d705e0 100644 --- a/vector/src/fdroid/java/im/vector/riotx/fdroid/package-info.kt +++ b/vector/src/fdroid/java/im/vector/riotx/fdroid/package-info.kt @@ -17,4 +17,4 @@ /** * Code exclusively used by the FDroid build and not referenced on the main source code */ -package im.vector.riotx.fdroid \ No newline at end of file +package im.vector.riotx.fdroid diff --git a/vector/src/fdroid/java/im/vector/riotx/fdroid/receiver/AlarmSyncBroadcastReceiver.kt b/vector/src/fdroid/java/im/vector/riotx/fdroid/receiver/AlarmSyncBroadcastReceiver.kt index 2c0738c2df..6648d79490 100644 --- a/vector/src/fdroid/java/im/vector/riotx/fdroid/receiver/AlarmSyncBroadcastReceiver.kt +++ b/vector/src/fdroid/java/im/vector/riotx/fdroid/receiver/AlarmSyncBroadcastReceiver.kt @@ -30,10 +30,8 @@ import timber.log.Timber class AlarmSyncBroadcastReceiver : BroadcastReceiver() { - override fun onReceive(context: Context, intent: Intent) { - - //Aquire a lock to give enough time for the sync :/ + // Aquire a lock to give enough time for the sync :/ (context.getSystemService(Context.POWER_SERVICE) as PowerManager).run { newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "riotx:fdroidSynclock").apply { acquire((10_000).toLong()) @@ -52,7 +50,7 @@ class AlarmSyncBroadcastReceiver : BroadcastReceiver() { context.startService(it) } } catch (ex: Throwable) { - //TODO + // TODO Timber.e(ex) } } @@ -66,7 +64,7 @@ class AlarmSyncBroadcastReceiver : BroadcastReceiver() { private const val REQUEST_CODE = 0 fun scheduleAlarm(context: Context, userId: String, delay: Long) { - //Reschedule + // Reschedule val intent = Intent(context, AlarmSyncBroadcastReceiver::class.java).apply { putExtra(SyncService.EXTRA_USER_ID, userId) } diff --git a/vector/src/fdroid/java/im/vector/riotx/fdroid/service/VectorSyncService.kt b/vector/src/fdroid/java/im/vector/riotx/fdroid/service/VectorSyncService.kt index b2a45eff81..fbf9c1a031 100644 --- a/vector/src/fdroid/java/im/vector/riotx/fdroid/service/VectorSyncService.kt +++ b/vector/src/fdroid/java/im/vector/riotx/fdroid/service/VectorSyncService.kt @@ -56,5 +56,4 @@ class VectorSyncService : SyncService() { } return super.onStartCommand(intent, flags, startId) } - -} \ No newline at end of file +} diff --git a/vector/src/fdroid/java/im/vector/riotx/push/fcm/FcmHelper.kt b/vector/src/fdroid/java/im/vector/riotx/push/fcm/FcmHelper.kt index 5775fc8479..bfd8850d00 100755 --- a/vector/src/fdroid/java/im/vector/riotx/push/fcm/FcmHelper.kt +++ b/vector/src/fdroid/java/im/vector/riotx/push/fcm/FcmHelper.kt @@ -14,6 +14,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +@file:Suppress("UNUSED_PARAMETER") + package im.vector.riotx.push.fcm import android.app.Activity @@ -64,7 +66,7 @@ object FcmHelper { } fun onEnterBackground(context: Context, vectorPreferences: VectorPreferences, activeSessionHolder: ActiveSessionHolder) { - //We need to use alarm in this mode + // We need to use alarm in this mode if (vectorPreferences.areNotificationEnabledForDevice() && activeSessionHolder.hasActiveSession()) { val currentSession = activeSessionHolder.getActiveSession() AlarmSyncBroadcastReceiver.scheduleAlarm(context, currentSession.myUserId, 4_000L) diff --git a/vector/src/fdroid/java/im/vector/riotx/push/fcm/NotificationTroubleshootTestManagerFactory.kt b/vector/src/fdroid/java/im/vector/riotx/push/fcm/NotificationTroubleshootTestManagerFactory.kt index e90ef5aa7d..25c06d5b6f 100644 --- a/vector/src/fdroid/java/im/vector/riotx/push/fcm/NotificationTroubleshootTestManagerFactory.kt +++ b/vector/src/fdroid/java/im/vector/riotx/push/fcm/NotificationTroubleshootTestManagerFactory.kt @@ -38,5 +38,4 @@ class NotificationTroubleshootTestManagerFactory @Inject constructor(private val mgr.addTest(testBackgroundRestrictions) return mgr } - -} \ No newline at end of file +} diff --git a/vector/src/gplay/java/im/vector/riotx/gplay/features/settings/troubleshoot/TestFirebaseToken.kt b/vector/src/gplay/java/im/vector/riotx/gplay/features/settings/troubleshoot/TestFirebaseToken.kt index 4d35c90464..3806893d98 100644 --- a/vector/src/gplay/java/im/vector/riotx/gplay/features/settings/troubleshoot/TestFirebaseToken.kt +++ b/vector/src/gplay/java/im/vector/riotx/gplay/features/settings/troubleshoot/TestFirebaseToken.kt @@ -39,7 +39,7 @@ class TestFirebaseToken @Inject constructor(private val context: AppCompatActivi .addOnCompleteListener(context) { task -> if (!task.isSuccessful) { val errorMsg = if (task.exception == null) "Unknown" else task.exception!!.localizedMessage - //Can't find where this constant is (not documented -or deprecated in docs- and all obfuscated) + // Can't find where this constant is (not documented -or deprecated in docs- and all obfuscated) if ("SERVICE_NOT_AVAILABLE".equals(errorMsg)) { description = stringProvider.getString(R.string.settings_troubleshoot_test_fcm_failed_service_not_available, errorMsg) } else if ("TOO_MANY_REGISTRATIONS".equals(errorMsg)) { @@ -56,7 +56,7 @@ class TestFirebaseToken @Inject constructor(private val context: AppCompatActivi } status = TestStatus.FAILED } else { - task.result?.token?.let {token -> + task.result?.token?.let { token -> val tok = token.substring(0, Math.min(8, token.length)) + "********************" description = stringProvider.getString(R.string.settings_troubleshoot_test_fcm_success, tok) Timber.e("Retrieved FCM token success [$tok].") @@ -71,5 +71,4 @@ class TestFirebaseToken @Inject constructor(private val context: AppCompatActivi status = TestStatus.FAILED } } - -} \ No newline at end of file +} diff --git a/vector/src/gplay/java/im/vector/riotx/gplay/features/settings/troubleshoot/TestPlayServices.kt b/vector/src/gplay/java/im/vector/riotx/gplay/features/settings/troubleshoot/TestPlayServices.kt index 2aaa0d2e83..c28a02d350 100644 --- a/vector/src/gplay/java/im/vector/riotx/gplay/features/settings/troubleshoot/TestPlayServices.kt +++ b/vector/src/gplay/java/im/vector/riotx/gplay/features/settings/troubleshoot/TestPlayServices.kt @@ -52,6 +52,4 @@ class TestPlayServices @Inject constructor(private val context: AppCompatActivit status = TestStatus.FAILED } } - } - diff --git a/vector/src/gplay/java/im/vector/riotx/gplay/features/settings/troubleshoot/TestTokenRegistration.kt b/vector/src/gplay/java/im/vector/riotx/gplay/features/settings/troubleshoot/TestTokenRegistration.kt index f53813af84..5468217527 100644 --- a/vector/src/gplay/java/im/vector/riotx/gplay/features/settings/troubleshoot/TestTokenRegistration.kt +++ b/vector/src/gplay/java/im/vector/riotx/gplay/features/settings/troubleshoot/TestTokenRegistration.kt @@ -38,7 +38,7 @@ class TestTokenRegistration @Inject constructor(private val context: AppCompatAc : TroubleshootTest(R.string.settings_troubleshoot_test_token_registration_title) { override fun perform() { - //Check if we have a registered pusher for this token + // Check if we have a registered pusher for this token val fcmToken = FcmHelper.getFcmToken(context) ?: run { status = TestStatus.FAILED return @@ -56,7 +56,7 @@ class TestTokenRegistration @Inject constructor(private val context: AppCompatAc quickFix = object : TroubleshootQuickFix(R.string.settings_troubleshoot_test_token_registration_quick_fix) { override fun doFix() { val workId = pushersManager.registerPusherWithFcmKey(fcmToken) - WorkManager.getInstance().getWorkInfoByIdLiveData(workId).observe(context, Observer { workInfo -> + WorkManager.getInstance(context).getWorkInfoByIdLiveData(workId).observe(context, Observer { workInfo -> if (workInfo != null) { if (workInfo.state == WorkInfo.State.SUCCEEDED) { manager?.retry() @@ -66,16 +66,12 @@ class TestTokenRegistration @Inject constructor(private val context: AppCompatAc } }) } - } status = TestStatus.FAILED - } else { description = stringProvider.getString(R.string.settings_troubleshoot_test_token_registration_success) status = TestStatus.SUCCESS } - } - -} \ No newline at end of file +} diff --git a/vector/src/gplay/java/im/vector/riotx/gplay/package-info.kt b/vector/src/gplay/java/im/vector/riotx/gplay/package-info.kt index 177fb56fd8..02e0382503 100644 --- a/vector/src/gplay/java/im/vector/riotx/gplay/package-info.kt +++ b/vector/src/gplay/java/im/vector/riotx/gplay/package-info.kt @@ -18,4 +18,3 @@ * Code exclusively used by the GPlay build and not referenced on the main source code */ package im.vector.riotx.gplay - diff --git a/vector/src/gplay/java/im/vector/riotx/gplay/push/fcm/VectorFirebaseMessagingService.kt b/vector/src/gplay/java/im/vector/riotx/gplay/push/fcm/VectorFirebaseMessagingService.kt index cde848ea41..7feb89879e 100755 --- a/vector/src/gplay/java/im/vector/riotx/gplay/push/fcm/VectorFirebaseMessagingService.kt +++ b/vector/src/gplay/java/im/vector/riotx/gplay/push/fcm/VectorFirebaseMessagingService.kt @@ -21,7 +21,6 @@ package im.vector.riotx.gplay.push.fcm import android.os.Handler import android.os.Looper -import android.text.TextUtils import androidx.lifecycle.Lifecycle import androidx.lifecycle.ProcessLifecycleOwner import com.google.firebase.messaging.FirebaseMessagingService @@ -73,23 +72,19 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() { * * @param message the message */ - override fun onMessageReceived(message: RemoteMessage?) { + override fun onMessageReceived(message: RemoteMessage) { if (!vectorPreferences.areNotificationEnabledForDevice()) { Timber.i("Notification are disabled for this device") return } - if (message == null || message.data == null) { - Timber.e("## onMessageReceived() : received a null message or message with no data") - return - } if (BuildConfig.LOW_PRIVACY_LOG_ENABLE) { Timber.i("## onMessageReceived() %s", message.data.toString()) Timber.i("## onMessageReceived() from FCM with priority %s", message.priority) } mUIHandler.post { if (ProcessLifecycleOwner.get().lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) { - //we are in foreground, let the sync do the things? + // we are in foreground, let the sync do the things? Timber.v("PUSH received in a foreground state, ignore") } else { onMessageReceivedInternal(message.data) @@ -103,15 +98,11 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() { * when the InstanceID token is initially generated, so this is where * you retrieve the token. */ - override fun onNewToken(refreshedToken: String?) { + override fun onNewToken(refreshedToken: String) { Timber.i("onNewToken: FCM Token has been updated") FcmHelper.storeFcmToken(this, refreshedToken) - if (refreshedToken == null) { - Timber.w("onNewToken:received null token") - } else { - if (vectorPreferences.areNotificationEnabledForDevice() && activeSessionHolder.hasActiveSession()) { - pusherManager.registerPusherWithFcmKey(refreshedToken) - } + if (vectorPreferences.areNotificationEnabledForDevice() && activeSessionHolder.hasActiveSession()) { + pusherManager.registerPusherWithFcmKey(refreshedToken) } } @@ -161,9 +152,8 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() { session.requireBackgroundSync() } } - } catch (e: Exception) { - Timber.e(e, "## onMessageReceivedInternal() failed : " + e.message) + Timber.e(e, "## onMessageReceivedInternal() failed") } } @@ -178,13 +168,11 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() { } catch (e: Exception) { Timber.e(e, "## isEventAlreadyKnown() : failed to check if the event was already defined") } - } return false } private fun handleNotificationWithoutSyncingMode(data: Map, session: Session?) { - if (session == null) { Timber.e("## handleNotificationWithoutSyncingMode cannot find session") return @@ -194,16 +182,16 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() { // This is required if the notification is about a particular Matrix event. // It may be omitted for notifications that only contain updated badge counts. // This ID can and should be used to detect duplicate notification requests. - val eventId = data["event_id"] ?: return //Just ignore + val eventId = data["event_id"] ?: return // Just ignore val eventType = data["type"] if (eventType == null) { - //Just add a generic unknown event + // Just add a generic unknown event val simpleNotifiableEvent = SimpleNotifiableEvent( session.myUserId, eventId, null, - true, //It's an issue in this case, all event will bing even if expected to be silent. + true, // It's an issue in this case, all event will bing even if expected to be silent. title = getString(R.string.notification_unknown_new_event), description = "", type = null, @@ -219,17 +207,16 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() { val notifiableEvent = notifiableEventResolver.resolveEvent(event, session) if (notifiableEvent == null) { - Timber.e("Unsupported notifiable event ${eventId}") + Timber.e("Unsupported notifiable event $eventId") if (BuildConfig.LOW_PRIVACY_LOG_ENABLE) { - Timber.e("--> ${event}") + Timber.e("--> $event") } } else { if (notifiableEvent is NotifiableMessageEvent) { - if (TextUtils.isEmpty(notifiableEvent.senderName)) { - notifiableEvent.senderName = data["sender_display_name"] - ?: data["sender"] ?: "" + if (notifiableEvent.senderName.isNullOrEmpty()) { + notifiableEvent.senderName = data["sender_display_name"] ?: data["sender"] ?: "" } - if (TextUtils.isEmpty(notifiableEvent.roomName)) { + if (notifiableEvent.roomName.isNullOrEmpty()) { notifiableEvent.roomName = findRoomNameBestEffort(data, session) ?: "" } } @@ -243,17 +230,11 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() { } private fun findRoomNameBestEffort(data: Map, session: Session?): String? { - val roomName: String? = data["room_name"] + var roomName: String? = data["room_name"] val roomId = data["room_id"] if (null == roomName && null != roomId) { // Try to get the room name from our store - /* - TODO - if (session?.dataHandler?.store?.isReady == true) { - val room = session.getRoom(roomId) - roomName = room?.getRoomDisplayName(this) - } - */ + roomName = session?.getRoom(roomId)?.roomSummary()?.displayName } return roomName } @@ -272,11 +253,11 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() { try { return Event(eventId = data["event_id"], - senderId = data["sender"], - roomId = data["room_id"], - type = data.getValue("type"), + senderId = data["sender"], + roomId = data["room_id"], + type = data.getValue("type"), // TODO content = data.getValue("content"), - originServerTs = System.currentTimeMillis()) + originServerTs = System.currentTimeMillis()) } catch (e: Exception) { Timber.e(e, "buildEvent fails ") } diff --git a/vector/src/gplay/java/im/vector/riotx/push/fcm/FcmHelper.kt b/vector/src/gplay/java/im/vector/riotx/push/fcm/FcmHelper.kt index 148a83368b..9f8dc6d7fc 100755 --- a/vector/src/gplay/java/im/vector/riotx/push/fcm/FcmHelper.kt +++ b/vector/src/gplay/java/im/vector/riotx/push/fcm/FcmHelper.kt @@ -37,7 +37,6 @@ import timber.log.Timber object FcmHelper { private val PREFS_KEY_FCM_TOKEN = "FCM_TOKEN" - fun isPushSupported(): Boolean = true /** @@ -62,7 +61,6 @@ object FcmHelper { .edit() .putString(PREFS_KEY_FCM_TOKEN, token) .apply() - } /** @@ -72,7 +70,7 @@ object FcmHelper { */ fun ensureFcmTokenIsRetrieved(activity: Activity, pushersManager: PushersManager) { // if (TextUtils.isEmpty(getFcmToken(activity))) { - //'app should always check the device for a compatible Google Play services APK before accessing Google Play services features' + // 'app should always check the device for a compatible Google Play services APK before accessing Google Play services features' if (checkPlayServices(activity)) { try { FirebaseInstanceId.getInstance().instanceId @@ -80,11 +78,10 @@ object FcmHelper { storeFcmToken(activity, instanceIdResult.token) pushersManager.registerPusherWithFcmKey(instanceIdResult.token) } - .addOnFailureListener(activity) { e -> Timber.e(e, "## ensureFcmTokenIsRetrieved() : failed " + e.message) } + .addOnFailureListener(activity) { e -> Timber.e(e, "## ensureFcmTokenIsRetrieved() : failed") } } catch (e: Throwable) { - Timber.e(e, "## ensureFcmTokenIsRetrieved() : failed " + e.message) + Timber.e(e, "## ensureFcmTokenIsRetrieved() : failed") } - } else { Toast.makeText(activity, R.string.no_valid_google_play_services_apk, Toast.LENGTH_SHORT).show() Timber.e("No valid Google Play Services found. Cannot use FCM.") @@ -102,10 +99,12 @@ object FcmHelper { return resultCode == ConnectionResult.SUCCESS } + @Suppress("UNUSED_PARAMETER") fun onEnterForeground(context: Context) { // No op } + @Suppress("UNUSED_PARAMETER") fun onEnterBackground(context: Context, vectorPreferences: VectorPreferences, activeSessionHolder: ActiveSessionHolder) { // TODO FCM fallback } diff --git a/vector/src/gplay/java/im/vector/riotx/push/fcm/NotificationTroubleshootTestManagerFactory.kt b/vector/src/gplay/java/im/vector/riotx/push/fcm/NotificationTroubleshootTestManagerFactory.kt index 3d2e45fed1..6f980197dd 100644 --- a/vector/src/gplay/java/im/vector/riotx/push/fcm/NotificationTroubleshootTestManagerFactory.kt +++ b/vector/src/gplay/java/im/vector/riotx/push/fcm/NotificationTroubleshootTestManagerFactory.kt @@ -45,5 +45,4 @@ class NotificationTroubleshootTestManagerFactory @Inject constructor(private val mgr.addTest(testTokenRegistration) return mgr } - -} \ No newline at end of file +} diff --git a/vector/src/gplay/google-services.json b/vector/src/gplay/release/google-services.json similarity index 100% rename from vector/src/gplay/google-services.json rename to vector/src/gplay/release/google-services.json diff --git a/vector/src/main/AndroidManifest.xml b/vector/src/main/AndroidManifest.xml index 01d8db467e..0c9bac61a1 100644 --- a/vector/src/main/AndroidManifest.xml +++ b/vector/src/main/AndroidManifest.xml @@ -4,6 +4,7 @@ package="im.vector.riotx"> + + + + + + + + + + + + + + + + + Copyright 2014 Leo Lin -
  • - FilePicker -
    - Copyright (c) 2018, Jaisel Rahman -
  • diff-match-patch
    @@ -354,8 +349,16 @@ SOFTWARE.
    Copyright (C) 2012-2017 Markus Junginger, greenrobot (http://greenrobot.org)
  • - - +
  • + LazyThreeTenBp +
    + Copyright 2017 Gabriel Ittner. +
  • +
  • + Android-multipicker-library +
    + Copyright 2018 Kumar Bibek +
  •  Apache License
    diff --git a/vector/src/main/java/im/vector/riotx/ActiveSessionObservableStore.kt b/vector/src/main/java/im/vector/riotx/ActiveSessionObservableStore.kt
    new file mode 100644
    index 0000000000..fd6a92e820
    --- /dev/null
    +++ b/vector/src/main/java/im/vector/riotx/ActiveSessionObservableStore.kt
    @@ -0,0 +1,27 @@
    +/*
    + * Copyright 2019 New Vector Ltd
    + *
    + * Licensed under the Apache License, Version 2.0 (the "License");
    + * you may not use this file except in compliance with the License.
    + * You may obtain a copy of the License at
    + *
    + * http://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing, software
    + * distributed under the License is distributed on an "AS IS" BASIS,
    + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    + * See the License for the specific language governing permissions and
    + * limitations under the License.
    + *
    + */
    +
    +package im.vector.riotx
    +
    +import arrow.core.Option
    +import im.vector.matrix.android.api.session.Session
    +import im.vector.riotx.core.utils.RxStore
    +import javax.inject.Inject
    +import javax.inject.Singleton
    +
    +@Singleton
    +class ActiveSessionObservableStore @Inject constructor() : RxStore>()
    diff --git a/vector/src/main/java/im/vector/riotx/AppStateHandler.kt b/vector/src/main/java/im/vector/riotx/AppStateHandler.kt
    new file mode 100644
    index 0000000000..76cbb9ef94
    --- /dev/null
    +++ b/vector/src/main/java/im/vector/riotx/AppStateHandler.kt
    @@ -0,0 +1,99 @@
    +/*
    + * Copyright 2019 New Vector Ltd
    + *
    + * Licensed under the Apache License, Version 2.0 (the "License");
    + * you may not use this file except in compliance with the License.
    + * You may obtain a copy of the License at
    + *
    + * http://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing, software
    + * distributed under the License is distributed on an "AS IS" BASIS,
    + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    + * See the License for the specific language governing permissions and
    + * limitations under the License.
    + */
    +
    +package im.vector.riotx
    +
    +import androidx.lifecycle.Lifecycle
    +import androidx.lifecycle.LifecycleObserver
    +import androidx.lifecycle.OnLifecycleEvent
    +import arrow.core.Option
    +import im.vector.matrix.android.api.session.group.model.GroupSummary
    +import im.vector.matrix.android.api.session.room.model.RoomSummary
    +import im.vector.matrix.rx.rx
    +import im.vector.riotx.features.home.HomeRoomListObservableStore
    +import im.vector.riotx.features.home.group.ALL_COMMUNITIES_GROUP_ID
    +import im.vector.riotx.features.home.group.SelectedGroupStore
    +import io.reactivex.Observable
    +import io.reactivex.android.schedulers.AndroidSchedulers
    +import io.reactivex.disposables.CompositeDisposable
    +import io.reactivex.functions.BiFunction
    +import io.reactivex.rxkotlin.addTo
    +import java.util.concurrent.TimeUnit
    +import javax.inject.Inject
    +import javax.inject.Singleton
    +
    +/**
    + * This class handles the global app state. At the moment, it only manages room list.
    + * It requires to be added to ProcessLifecycleOwner.get().lifecycle
    + */
    +@Singleton
    +class AppStateHandler @Inject constructor(
    +        private val sessionObservableStore: ActiveSessionObservableStore,
    +        private val homeRoomListObservableStore: HomeRoomListObservableStore,
    +        private val selectedGroupStore: SelectedGroupStore) : LifecycleObserver {
    +
    +    private val compositeDisposable = CompositeDisposable()
    +
    +    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    +    fun entersForeground() {
    +        observeRoomsAndGroup()
    +    }
    +
    +    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    +    fun entersBackground() {
    +        compositeDisposable.clear()
    +    }
    +
    +    private fun observeRoomsAndGroup() {
    +        Observable
    +                .combineLatest, Option, List>(
    +                        sessionObservableStore.observe()
    +                                .observeOn(AndroidSchedulers.mainThread())
    +                                .switchMap {
    +                                    it.orNull()?.rx()?.liveRoomSummaries()
    +                                    ?: Observable.just(emptyList())
    +                                }
    +                                .throttleLast(300, TimeUnit.MILLISECONDS),
    +                        selectedGroupStore.observe(),
    +                        BiFunction { rooms, selectedGroupOption ->
    +                            val selectedGroup = selectedGroupOption.orNull()
    +                            val filteredDirectRooms = rooms
    +                                    .filter { it.isDirect }
    +                                    .filter {
    +                                        if (selectedGroup == null || selectedGroup.groupId == ALL_COMMUNITIES_GROUP_ID) {
    +                                            true
    +                                        } else {
    +                                            it.otherMemberIds
    +                                                    .intersect(selectedGroup.userIds)
    +                                                    .isNotEmpty()
    +                                        }
    +                                    }
    +
    +                            val filteredGroupRooms = rooms
    +                                    .filter { !it.isDirect }
    +                                    .filter {
    +                                        selectedGroup?.groupId == ALL_COMMUNITIES_GROUP_ID
    +                                        || selectedGroup?.roomIds?.contains(it.roomId) ?: true
    +                                    }
    +                            filteredDirectRooms + filteredGroupRooms
    +                        }
    +                )
    +                .subscribe {
    +                    homeRoomListObservableStore.post(it)
    +                }
    +                .addTo(compositeDisposable)
    +    }
    +}
    diff --git a/vector/src/main/java/im/vector/riotx/EmojiCompatFontProvider.kt b/vector/src/main/java/im/vector/riotx/EmojiCompatFontProvider.kt
    index 24e7e6d287..0a338ce042 100644
    --- a/vector/src/main/java/im/vector/riotx/EmojiCompatFontProvider.kt
    +++ b/vector/src/main/java/im/vector/riotx/EmojiCompatFontProvider.kt
    @@ -59,8 +59,7 @@ class EmojiCompatFontProvider @Inject constructor(): FontsContractCompat.FontReq
             listeners.remove(listener)
         }
     
    -
         interface FontProviderListener {
             fun compatibilityFontUpdate(typeface: Typeface?)
         }
    -}
    \ No newline at end of file
    +}
    diff --git a/vector/src/main/java/im/vector/riotx/EmojiCompatWrapper.kt b/vector/src/main/java/im/vector/riotx/EmojiCompatWrapper.kt
    index b183284084..945ddaec5a 100644
    --- a/vector/src/main/java/im/vector/riotx/EmojiCompatWrapper.kt
    +++ b/vector/src/main/java/im/vector/riotx/EmojiCompatWrapper.kt
    @@ -16,7 +16,6 @@
     package im.vector.riotx
     
     import android.content.Context
    -import androidx.appcompat.app.AppCompatActivity
     import androidx.core.provider.FontRequest
     import androidx.emoji.text.EmojiCompat
     import androidx.emoji.text.FontRequestEmojiCompatConfig
    @@ -30,12 +29,11 @@ class EmojiCompatWrapper @Inject constructor(private val context: Context)  {
         private var initialized = false
     
         fun init(fontRequest: FontRequest) {
    -
    -        //Use emoji compat for the benefit of emoji spans
    +        // Use emoji compat for the benefit of emoji spans
             val config = FontRequestEmojiCompatConfig(context, fontRequest)
                     // we want to replace all emojis with selected font
                     .setReplaceAll(true)
    -        //Debug options
    +        // Debug options
     //                .setEmojiSpanIndicatorEnabled(true)
     //                .setEmojiSpanIndicatorColor(Color.GREEN)
             EmojiCompat.init(config)
    @@ -56,7 +54,7 @@ class EmojiCompatWrapper @Inject constructor(private val context: Context)  {
                 try {
                     return EmojiCompat.get().process(sequence)
                 } catch (throwable: Throwable) {
    -                //Defensive coding against error (should not happend as it is initialized)
    +                // Defensive coding against error (should not happend as it is initialized)
                     Timber.e(throwable, "Failed to init EmojiCompat")
                     return sequence
                 }
    @@ -64,4 +62,4 @@ class EmojiCompatWrapper @Inject constructor(private val context: Context)  {
                 return sequence
             }
         }
    -}
    \ No newline at end of file
    +}
    diff --git a/vector/src/main/java/im/vector/riotx/VectorApplication.kt b/vector/src/main/java/im/vector/riotx/VectorApplication.kt
    index bf56e71915..b1fd6a8485 100644
    --- a/vector/src/main/java/im/vector/riotx/VectorApplication.kt
    +++ b/vector/src/main/java/im/vector/riotx/VectorApplication.kt
    @@ -31,9 +31,9 @@ import androidx.multidex.MultiDex
     import com.airbnb.epoxy.EpoxyAsyncUtil
     import com.airbnb.epoxy.EpoxyController
     import com.facebook.stetho.Stetho
    +import com.gabrielittner.threetenbp.LazyThreeTen
     import com.github.piasy.biv.BigImageViewer
     import com.github.piasy.biv.loader.glide.GlideImageLoader
    -import com.jakewharton.threetenabp.AndroidThreeTen
     import im.vector.matrix.android.api.Matrix
     import im.vector.matrix.android.api.MatrixConfiguration
     import im.vector.matrix.android.api.auth.Authenticator
    @@ -49,6 +49,7 @@ import im.vector.riotx.features.notifications.NotificationDrawerManager
     import im.vector.riotx.features.notifications.NotificationUtils
     import im.vector.riotx.features.notifications.PushRuleTriggerListener
     import im.vector.riotx.features.rageshake.VectorUncaughtExceptionHandler
    +import im.vector.riotx.features.session.SessionListener
     import im.vector.riotx.features.settings.VectorPreferences
     import im.vector.riotx.features.version.VersionProvider
     import im.vector.riotx.push.fcm.FcmHelper
    @@ -59,27 +60,26 @@ import javax.inject.Inject
     
     class VectorApplication : Application(), HasVectorInjector, MatrixConfiguration.Provider, androidx.work.Configuration.Provider {
     
    -
         lateinit var appContext: Context
    -    //font thread handler
    +    // font thread handler
         @Inject lateinit var authenticator: Authenticator
         @Inject lateinit var vectorConfiguration: VectorConfiguration
         @Inject lateinit var emojiCompatFontProvider: EmojiCompatFontProvider
         @Inject lateinit var emojiCompatWrapper: EmojiCompatWrapper
         @Inject lateinit var vectorUncaughtExceptionHandler: VectorUncaughtExceptionHandler
         @Inject lateinit var activeSessionHolder: ActiveSessionHolder
    +    @Inject lateinit var sessionListener: SessionListener
         @Inject lateinit var notificationDrawerManager: NotificationDrawerManager
         @Inject lateinit var pushRuleTriggerListener: PushRuleTriggerListener
         @Inject lateinit var vectorPreferences: VectorPreferences
         @Inject lateinit var versionProvider: VersionProvider
         @Inject lateinit var notificationUtils: NotificationUtils
    +    @Inject lateinit var appStateHandler: AppStateHandler
         lateinit var vectorComponent: VectorComponent
         private var fontThreadHandler: Handler? = null
     
    -
     //    var slowMode = false
     
    -
         override fun onCreate() {
             super.onCreate()
             appContext = this
    @@ -96,7 +96,8 @@ class VectorApplication : Application(), HasVectorInjector, MatrixConfiguration.
                 Stetho.initializeWithDefaults(this)
             }
             logInfo()
    -        AndroidThreeTen.init(this)
    +        LazyThreeTen.init(this)
    +
             BigImageViewer.initialize(GlideImageLoader.with(applicationContext))
             EpoxyController.defaultDiffingHandler = EpoxyAsyncUtil.getAsyncBackgroundHandler()
             EpoxyController.defaultModelBuildingHandler = EpoxyAsyncUtil.getAsyncBackgroundHandler()
    @@ -116,10 +117,9 @@ class VectorApplication : Application(), HasVectorInjector, MatrixConfiguration.
             if (authenticator.hasAuthenticatedSessions() && !activeSessionHolder.hasActiveSession()) {
                 val lastAuthenticatedSession = authenticator.getLastAuthenticatedSession()!!
                 activeSessionHolder.setActiveSession(lastAuthenticatedSession)
    -            lastAuthenticatedSession.configureAndStart(pushRuleTriggerListener)
    +            lastAuthenticatedSession.configureAndStart(pushRuleTriggerListener, sessionListener)
             }
             ProcessLifecycleOwner.get().lifecycle.addObserver(object : LifecycleObserver {
    -
                 @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
                 fun entersForeground() {
                     FcmHelper.onEnterForeground(appContext)
    @@ -135,7 +135,8 @@ class VectorApplication : Application(), HasVectorInjector, MatrixConfiguration.
                     FcmHelper.onEnterBackground(appContext, vectorPreferences, activeSessionHolder)
                 }
             })
    -        //This should be done as early as possible
    +        ProcessLifecycleOwner.get().lifecycle.addObserver(appStateHandler)
    +        // This should be done as early as possible
             initKnownEmojiHashSet(appContext)
         }
     
    @@ -168,7 +169,7 @@ class VectorApplication : Application(), HasVectorInjector, MatrixConfiguration.
     
         override fun onConfigurationChanged(newConfig: Configuration?) {
             super.onConfigurationChanged(newConfig)
    -        vectorConfiguration.onConfigurationChanged(newConfig)
    +        vectorConfiguration.onConfigurationChanged()
         }
     
         private fun getFontThreadHandler(): Handler {
    @@ -182,5 +183,4 @@ class VectorApplication : Application(), HasVectorInjector, MatrixConfiguration.
             handlerThread.start()
             return Handler(handlerThread.looper)
         }
    -
    -}
    \ No newline at end of file
    +}
    diff --git a/vector/src/main/java/im/vector/riotx/core/animations/SimpleAnimatorListener.kt b/vector/src/main/java/im/vector/riotx/core/animations/SimpleAnimatorListener.kt
    index 5968ee19c4..1819e003f9 100644
    --- a/vector/src/main/java/im/vector/riotx/core/animations/SimpleAnimatorListener.kt
    +++ b/vector/src/main/java/im/vector/riotx/core/animations/SimpleAnimatorListener.kt
    @@ -34,4 +34,4 @@ open class SimpleAnimatorListener : Animator.AnimatorListener {
         override fun onAnimationStart(animation: Animator?) {
             // No op
         }
    -}
    \ No newline at end of file
    +}
    diff --git a/vector/src/main/java/im/vector/riotx/core/animations/SimpleTransitionListener.kt b/vector/src/main/java/im/vector/riotx/core/animations/SimpleTransitionListener.kt
    index a83b0cffe5..728127b374 100644
    --- a/vector/src/main/java/im/vector/riotx/core/animations/SimpleTransitionListener.kt
    +++ b/vector/src/main/java/im/vector/riotx/core/animations/SimpleTransitionListener.kt
    @@ -38,4 +38,4 @@ open class SimpleTransitionListener : Transition.TransitionListener {
         override fun onTransitionStart(transition: Transition) {
             // No op
         }
    -}
    \ No newline at end of file
    +}
    diff --git a/vector/src/main/java/im/vector/riotx/core/animations/VectorFullTransitionSet.kt b/vector/src/main/java/im/vector/riotx/core/animations/VectorFullTransitionSet.kt
    index d2d9a224c4..83bc6f0d01 100644
    --- a/vector/src/main/java/im/vector/riotx/core/animations/VectorFullTransitionSet.kt
    +++ b/vector/src/main/java/im/vector/riotx/core/animations/VectorFullTransitionSet.kt
    @@ -40,5 +40,4 @@ class VectorFullTransitionSet : TransitionSet {
                     .addTransition(ChangeTransform())
                     .addTransition(Fade(Fade.IN))
         }
    -
     }
    diff --git a/vector/src/main/java/im/vector/riotx/core/date/VectorDateFormatter.kt b/vector/src/main/java/im/vector/riotx/core/date/VectorDateFormatter.kt
    index f8e8d61220..367615d765 100644
    --- a/vector/src/main/java/im/vector/riotx/core/date/VectorDateFormatter.kt
    +++ b/vector/src/main/java/im/vector/riotx/core/date/VectorDateFormatter.kt
    @@ -23,7 +23,6 @@ import org.threeten.bp.LocalDateTime
     import org.threeten.bp.format.DateTimeFormatter
     import javax.inject.Inject
     
    -
     class VectorDateFormatter @Inject constructor(private val context: Context,
                                                   private val localeProvider: LocaleProvider) {
     
    @@ -53,5 +52,4 @@ class VectorDateFormatter @Inject constructor(private val context: Context,
                                                        DateUtils.FORMAT_SHOW_WEEKDAY
             ).toString()
         }
    -
    -}
    \ No newline at end of file
    +}
    diff --git a/vector/src/main/java/im/vector/riotx/core/di/ActiveSessionHolder.kt b/vector/src/main/java/im/vector/riotx/core/di/ActiveSessionHolder.kt
    index 5f29a76f10..da3c041a1c 100644
    --- a/vector/src/main/java/im/vector/riotx/core/di/ActiveSessionHolder.kt
    +++ b/vector/src/main/java/im/vector/riotx/core/di/ActiveSessionHolder.kt
    @@ -16,8 +16,10 @@
     
     package im.vector.riotx.core.di
     
    +import arrow.core.Option
     import im.vector.matrix.android.api.auth.Authenticator
     import im.vector.matrix.android.api.session.Session
    +import im.vector.riotx.ActiveSessionObservableStore
     import im.vector.riotx.features.crypto.keysrequest.KeyRequestHandler
     import im.vector.riotx.features.crypto.verification.IncomingVerificationRequestHandler
     import java.util.concurrent.atomic.AtomicReference
    @@ -26,6 +28,7 @@ import javax.inject.Singleton
     
     @Singleton
     class ActiveSessionHolder @Inject constructor(private val authenticator: Authenticator,
    +                                              private val sessionObservableStore: ActiveSessionObservableStore,
                                                   private val keyRequestHandler: KeyRequestHandler,
                                                   private val incomingVerificationRequestHandler: IncomingVerificationRequestHandler
     ) {
    @@ -34,12 +37,14 @@ class ActiveSessionHolder @Inject constructor(private val authenticator: Authent
     
         fun setActiveSession(session: Session) {
             activeSession.set(session)
    +        sessionObservableStore.post(Option.fromNullable(session))
             keyRequestHandler.start(session)
             incomingVerificationRequestHandler.start(session)
         }
     
         fun clearActiveSession() {
             activeSession.set(null)
    +        sessionObservableStore.post(Option.empty())
             keyRequestHandler.stop()
             incomingVerificationRequestHandler.stop()
         }
    @@ -57,10 +62,9 @@ class ActiveSessionHolder @Inject constructor(private val authenticator: Authent
                     ?: throw IllegalStateException("You should authenticate before using this")
         }
     
    -    //TODO: Stop sync ?
    +    // TODO: Stop sync ?
     //    fun switchToSession(sessionParams: SessionParams) {
     //        val newActiveSession = authenticator.getSession(sessionParams)
     //        activeSession.set(newActiveSession)
     //    }
    -
    -}
    \ No newline at end of file
    +}
    diff --git a/vector/src/main/java/im/vector/riotx/core/di/AssistedInjectModule.kt b/vector/src/main/java/im/vector/riotx/core/di/AssistedInjectModule.kt
    index 915780dba2..17e0bd71e5 100644
    --- a/vector/src/main/java/im/vector/riotx/core/di/AssistedInjectModule.kt
    +++ b/vector/src/main/java/im/vector/riotx/core/di/AssistedInjectModule.kt
    @@ -21,4 +21,4 @@ import dagger.Module
     
     @AssistedModule
     @Module(includes = [AssistedInject_AssistedInjectModule::class])
    -interface AssistedInjectModule
    \ No newline at end of file
    +interface AssistedInjectModule
    diff --git a/vector/src/main/java/im/vector/riotx/core/di/HasScreenInjector.kt b/vector/src/main/java/im/vector/riotx/core/di/HasScreenInjector.kt
    index 44594971a0..62e359c0ae 100644
    --- a/vector/src/main/java/im/vector/riotx/core/di/HasScreenInjector.kt
    +++ b/vector/src/main/java/im/vector/riotx/core/di/HasScreenInjector.kt
    @@ -19,5 +19,4 @@ package im.vector.riotx.core.di
     interface HasScreenInjector {
     
         fun injector(): ScreenComponent
    -
    -}
    \ No newline at end of file
    +}
    diff --git a/vector/src/main/java/im/vector/riotx/core/di/HasVectorInjector.kt b/vector/src/main/java/im/vector/riotx/core/di/HasVectorInjector.kt
    index 2058133b68..c141f0e9e1 100644
    --- a/vector/src/main/java/im/vector/riotx/core/di/HasVectorInjector.kt
    +++ b/vector/src/main/java/im/vector/riotx/core/di/HasVectorInjector.kt
    @@ -19,5 +19,4 @@ package im.vector.riotx.core.di
     interface HasVectorInjector {
     
         fun injector(): VectorComponent
    -
    -}
    \ No newline at end of file
    +}
    diff --git a/vector/src/main/java/im/vector/riotx/core/di/ScreenComponent.kt b/vector/src/main/java/im/vector/riotx/core/di/ScreenComponent.kt
    index 01db4b4a01..0efbc0e173 100644
    --- a/vector/src/main/java/im/vector/riotx/core/di/ScreenComponent.kt
    +++ b/vector/src/main/java/im/vector/riotx/core/di/ScreenComponent.kt
    @@ -41,9 +41,12 @@ import im.vector.riotx.features.home.createdirect.CreateDirectRoomKnownUsersFrag
     import im.vector.riotx.features.home.group.GroupListFragment
     import im.vector.riotx.features.home.room.detail.RoomDetailFragment
     import im.vector.riotx.features.home.room.detail.readreceipts.DisplayReadReceiptsBottomSheet
    -import im.vector.riotx.features.home.room.detail.timeline.action.*
    +import im.vector.riotx.features.home.room.detail.timeline.action.MessageActionsBottomSheet
    +import im.vector.riotx.features.home.room.detail.timeline.edithistory.ViewEditHistoryBottomSheet
    +import im.vector.riotx.features.home.room.detail.timeline.reactions.ViewReactionsBottomSheet
     import im.vector.riotx.features.home.room.filtered.FilteredRoomsActivity
     import im.vector.riotx.features.home.room.list.RoomListFragment
    +import im.vector.riotx.features.home.room.list.RoomListModule
     import im.vector.riotx.features.invite.VectorInviteView
     import im.vector.riotx.features.link.LinkHandlerActivity
     import im.vector.riotx.features.login.LoginActivity
    @@ -65,8 +68,20 @@ import im.vector.riotx.features.roomdirectory.picker.RoomDirectoryPickerFragment
     import im.vector.riotx.features.roomdirectory.roompreview.RoomPreviewNoPreviewFragment
     import im.vector.riotx.features.settings.*
     import im.vector.riotx.features.settings.push.PushGatewaysFragment
    +import im.vector.riotx.features.share.IncomingShareActivity
    +import im.vector.riotx.features.ui.UiStateRepository
     
    -@Component(dependencies = [VectorComponent::class], modules = [AssistedInjectModule::class, ViewModelModule::class, HomeModule::class])
    +@Component(
    +        dependencies = [
    +            VectorComponent::class
    +        ],
    +        modules = [
    +            AssistedInjectModule::class,
    +            ViewModelModule::class,
    +            HomeModule::class,
    +            RoomListModule::class
    +        ]
    +)
     @ScreenScope
     interface ScreenComponent {
     
    @@ -80,6 +95,8 @@ interface ScreenComponent {
     
         fun navigator(): Navigator
     
    +    fun uiStateRepository(): UiStateRepository
    +
         fun inject(activity: HomeActivity)
     
         fun inject(roomDetailFragment: RoomDetailFragment)
    @@ -100,12 +117,10 @@ interface ScreenComponent {
     
         fun inject(messageActionsBottomSheet: MessageActionsBottomSheet)
     
    -    fun inject(viewReactionBottomSheet: ViewReactionBottomSheet)
    +    fun inject(viewReactionsBottomSheet: ViewReactionsBottomSheet)
     
         fun inject(viewEditHistoryBottomSheet: ViewEditHistoryBottomSheet)
     
    -    fun inject(messageMenuFragment: MessageMenuFragment)
    -
         fun inject(vectorSettingsActivity: VectorSettingsActivity)
     
         fun inject(createRoomFragment: CreateRoomFragment)
    @@ -132,8 +147,6 @@ interface ScreenComponent {
     
         fun inject(sasVerificationIncomingFragment: SASVerificationIncomingFragment)
     
    -    fun inject(quickReactionFragment: QuickReactionFragment)
    -
         fun inject(emojiReactionPickerActivity: EmojiReactionPickerActivity)
     
         fun inject(loginActivity: LoginActivity)
    @@ -182,6 +195,8 @@ interface ScreenComponent {
     
         fun inject(reactionButton: ReactionButton)
     
    +    fun inject(incomingShareActivity: IncomingShareActivity)
    +
         @Component.Factory
         interface Factory {
             fun create(vectorComponent: VectorComponent,
    diff --git a/vector/src/main/java/im/vector/riotx/core/di/ScreenModule.kt b/vector/src/main/java/im/vector/riotx/core/di/ScreenModule.kt
    index 64c0f34ce8..1073a59f7c 100644
    --- a/vector/src/main/java/im/vector/riotx/core/di/ScreenModule.kt
    +++ b/vector/src/main/java/im/vector/riotx/core/di/ScreenModule.kt
    @@ -27,5 +27,4 @@ object ScreenModule {
         @Provides
         @JvmStatic
         fun providesGlideRequests(context: AppCompatActivity) = GlideApp.with(context)
    -
    -}
    \ No newline at end of file
    +}
    diff --git a/vector/src/main/java/im/vector/riotx/core/di/VectorComponent.kt b/vector/src/main/java/im/vector/riotx/core/di/VectorComponent.kt
    index a76091fb36..2dfbb5f799 100644
    --- a/vector/src/main/java/im/vector/riotx/core/di/VectorComponent.kt
    +++ b/vector/src/main/java/im/vector/riotx/core/di/VectorComponent.kt
    @@ -23,6 +23,7 @@ import dagger.Component
     import im.vector.matrix.android.api.Matrix
     import im.vector.matrix.android.api.auth.Authenticator
     import im.vector.matrix.android.api.session.Session
    +import im.vector.riotx.ActiveSessionObservableStore
     import im.vector.riotx.EmojiCompatFontProvider
     import im.vector.riotx.EmojiCompatWrapper
     import im.vector.riotx.VectorApplication
    @@ -32,7 +33,6 @@ import im.vector.riotx.features.configuration.VectorConfiguration
     import im.vector.riotx.features.crypto.keysrequest.KeyRequestHandler
     import im.vector.riotx.features.crypto.verification.IncomingVerificationRequestHandler
     import im.vector.riotx.features.home.AvatarRenderer
    -import im.vector.riotx.features.home.HomeNavigator
     import im.vector.riotx.features.home.HomeRoomListObservableStore
     import im.vector.riotx.features.home.group.SelectedGroupStore
     import im.vector.riotx.features.html.EventHtmlRenderer
    @@ -41,19 +41,24 @@ import im.vector.riotx.features.notifications.*
     import im.vector.riotx.features.rageshake.BugReporter
     import im.vector.riotx.features.rageshake.VectorFileLogger
     import im.vector.riotx.features.rageshake.VectorUncaughtExceptionHandler
    +import im.vector.riotx.features.session.SessionListener
     import im.vector.riotx.features.settings.VectorPreferences
    +import im.vector.riotx.features.share.ShareRoomListObservableStore
    +import im.vector.riotx.features.ui.UiStateRepository
     import javax.inject.Singleton
     
     @Component(modules = [VectorModule::class])
     @Singleton
     interface VectorComponent {
     
    -    fun inject(vectorApplication: NotificationBroadcastReceiver)
    +    fun inject(notificationBroadcastReceiver: NotificationBroadcastReceiver)
     
         fun inject(vectorApplication: VectorApplication)
     
         fun matrix(): Matrix
     
    +    fun sessionListener(): SessionListener
    +
         fun currentSession(): Session
     
         fun notificationUtils(): NotificationUtils
    @@ -64,7 +69,7 @@ interface VectorComponent {
     
         fun resources(): Resources
     
    -    fun dimensionUtils(): DimensionConverter
    +    fun dimensionConverter(): DimensionConverter
     
         fun vectorConfiguration(): VectorConfiguration
     
    @@ -80,12 +85,14 @@ interface VectorComponent {
     
         fun navigator(): Navigator
     
    -    fun homeNavigator(): HomeNavigator
    -
         fun homeRoomListObservableStore(): HomeRoomListObservableStore
     
    +    fun shareRoomListObservableStore(): ShareRoomListObservableStore
    +
         fun selectedGroupStore(): SelectedGroupStore
     
    +    fun activeSessionObservableStore(): ActiveSessionObservableStore
    +
         fun incomingVerificationRequestHandler(): IncomingVerificationRequestHandler
     
         fun incomingKeyRequestHandler(): KeyRequestHandler
    @@ -106,9 +113,10 @@ interface VectorComponent {
     
         fun vectorFileLogger(): VectorFileLogger
     
    +    fun uiStateRepository(): UiStateRepository
    +
         @Component.Factory
         interface Factory {
             fun create(@BindsInstance context: Context): VectorComponent
         }
    -
    -}
    \ No newline at end of file
    +}
    diff --git a/vector/src/main/java/im/vector/riotx/core/di/VectorModule.kt b/vector/src/main/java/im/vector/riotx/core/di/VectorModule.kt
    index 251fc0b1e9..e3df0eb635 100644
    --- a/vector/src/main/java/im/vector/riotx/core/di/VectorModule.kt
    +++ b/vector/src/main/java/im/vector/riotx/core/di/VectorModule.kt
    @@ -28,6 +28,8 @@ import im.vector.matrix.android.api.auth.Authenticator
     import im.vector.matrix.android.api.session.Session
     import im.vector.riotx.features.navigation.DefaultNavigator
     import im.vector.riotx.features.navigation.Navigator
    +import im.vector.riotx.features.ui.SharedPreferencesUiStateRepository
    +import im.vector.riotx.features.ui.UiStateRepository
     
     @Module
     abstract class VectorModule {
    @@ -56,13 +58,13 @@ abstract class VectorModule {
             @Provides
             @JvmStatic
             fun providesCurrentSession(activeSessionHolder: ActiveSessionHolder): Session {
    -            //TODO: handle session injection better
    +            // TODO: handle session injection better
                 return activeSessionHolder.getActiveSession()
             }
     
             @Provides
             @JvmStatic
    -        fun providesAuthenticator(matrix: Matrix): Authenticator{
    +        fun providesAuthenticator(matrix: Matrix): Authenticator {
                 return matrix.authenticator()
             }
         }
    @@ -70,5 +72,6 @@ abstract class VectorModule {
         @Binds
         abstract fun bindNavigator(navigator: DefaultNavigator): Navigator
     
    -
    -}
    \ No newline at end of file
    +    @Binds
    +    abstract fun bindUiStateRepository(uiStateRepository: SharedPreferencesUiStateRepository): UiStateRepository
    +}
    diff --git a/vector/src/main/java/im/vector/riotx/core/di/ViewModelKey.kt b/vector/src/main/java/im/vector/riotx/core/di/ViewModelKey.kt
    index 09be563398..09c8aadb51 100644
    --- a/vector/src/main/java/im/vector/riotx/core/di/ViewModelKey.kt
    +++ b/vector/src/main/java/im/vector/riotx/core/di/ViewModelKey.kt
    @@ -23,4 +23,4 @@ import kotlin.reflect.KClass
     @Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
     @Retention(AnnotationRetention.RUNTIME)
     @MapKey
    -annotation class ViewModelKey(val value: KClass)
    \ No newline at end of file
    +annotation class ViewModelKey(val value: KClass)
    diff --git a/vector/src/main/java/im/vector/riotx/core/di/ViewModelModule.kt b/vector/src/main/java/im/vector/riotx/core/di/ViewModelModule.kt
    index 954b067d20..98c89c421a 100644
    --- a/vector/src/main/java/im/vector/riotx/core/di/ViewModelModule.kt
    +++ b/vector/src/main/java/im/vector/riotx/core/di/ViewModelModule.kt
    @@ -100,5 +100,4 @@ interface ViewModelModule {
         @IntoMap
         @ViewModelKey(CreateDirectRoomNavigationViewModel::class)
         fun bindCreateDirectRoomNavigationViewModel(viewModel: CreateDirectRoomNavigationViewModel): ViewModel
    -
    -}
    \ No newline at end of file
    +}
    diff --git a/vector/src/main/java/im/vector/riotx/core/dialogs/DialogAdapter.kt b/vector/src/main/java/im/vector/riotx/core/dialogs/DialogAdapter.kt
    deleted file mode 100644
    index 49d865e8cf..0000000000
    --- a/vector/src/main/java/im/vector/riotx/core/dialogs/DialogAdapter.kt
    +++ /dev/null
    @@ -1,43 +0,0 @@
    -/*
    - * Copyright 2019 New Vector Ltd
    - *
    - * Licensed under the Apache License, Version 2.0 (the "License");
    - * you may not use this file except in compliance with the License.
    - * You may obtain a copy of the License at
    - *
    - * http://www.apache.org/licenses/LICENSE-2.0
    - *
    - * Unless required by applicable law or agreed to in writing, software
    - * distributed under the License is distributed on an "AS IS" BASIS,
    - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    - * See the License for the specific language governing permissions and
    - * limitations under the License.
    - */
    -
    -package im.vector.riotx.core.dialogs
    -
    -import android.content.Context
    -import android.view.LayoutInflater
    -import android.view.View
    -import android.view.ViewGroup
    -import android.widget.ArrayAdapter
    -import im.vector.riotx.R
    -
    -internal abstract class DialogAdapter(context: Context) : ArrayAdapter(context, R.layout.item_dialog) {
    -
    -    override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
    -        val view: View
    -        if (convertView == null) {
    -            view = LayoutInflater.from(context).inflate(R.layout.item_dialog, parent, false)
    -            view.tag = DialogListItemHolder(view)
    -        } else {
    -            view = convertView
    -        }
    -        with(view.tag as DialogListItemHolder) {
    -            icon.setImageResource(getItem(position).iconRes)
    -            text.setText(getItem(position).titleRes)
    -        }
    -        return view
    -    }
    -
    -}
    diff --git a/vector/src/main/java/im/vector/riotx/core/dialogs/DialogListItem.kt b/vector/src/main/java/im/vector/riotx/core/dialogs/DialogListItem.kt
    deleted file mode 100644
    index 1486e870f3..0000000000
    --- a/vector/src/main/java/im/vector/riotx/core/dialogs/DialogListItem.kt
    +++ /dev/null
    @@ -1,36 +0,0 @@
    -/*
    - * Copyright 2019 New Vector Ltd
    - *
    - * Licensed under the Apache License, Version 2.0 (the "License");
    - * you may not use this file except in compliance with the License.
    - * You may obtain a copy of the License at
    - *
    - * http://www.apache.org/licenses/LICENSE-2.0
    - *
    - * Unless required by applicable law or agreed to in writing, software
    - * distributed under the License is distributed on an "AS IS" BASIS,
    - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    - * See the License for the specific language governing permissions and
    - * limitations under the License.
    - */
    -
    -package im.vector.riotx.core.dialogs
    -
    -import androidx.annotation.DrawableRes
    -import androidx.annotation.StringRes
    -import im.vector.riotx.R
    -
    -internal sealed class DialogListItem(@DrawableRes val iconRes: Int,
    -                                     @StringRes val titleRes: Int) {
    -
    -    object StartVoiceCall : DialogListItem(R.drawable.voice_call_green, R.string.action_voice_call)
    -    object StartVideoCall : DialogListItem(R.drawable.video_call_green, R.string.action_video_call)
    -
    -    object SendFile : DialogListItem(R.drawable.ic_material_file, R.string.option_send_files)
    -    object SendVoice : DialogListItem(R.drawable.vector_micro_green, R.string.option_send_voice)
    -    object SendSticker : DialogListItem(R.drawable.ic_send_sticker, R.string.option_send_sticker)
    -    object TakePhoto : DialogListItem(R.drawable.ic_material_camera, R.string.option_take_photo)
    -    object TakeVideo : DialogListItem(R.drawable.ic_material_videocam, R.string.option_take_video)
    -    object TakePhotoVideo : DialogListItem(R.drawable.ic_material_camera, R.string.option_take_photo_video)
    -
    -}
    diff --git a/vector/src/main/java/im/vector/riotx/core/dialogs/DialogLocker.kt b/vector/src/main/java/im/vector/riotx/core/dialogs/DialogLocker.kt
    index 60397fb6b6..a6c1558948 100644
    --- a/vector/src/main/java/im/vector/riotx/core/dialogs/DialogLocker.kt
    +++ b/vector/src/main/java/im/vector/riotx/core/dialogs/DialogLocker.kt
    @@ -62,5 +62,4 @@ class DialogLocker(savedInstanceState: Bundle?) : Restorable {
         override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
             isDialogDisplayed = savedInstanceState?.getBoolean(KEY_DIALOG_IS_DISPLAYED, false) == true
         }
    -
    -}
    \ No newline at end of file
    +}
    diff --git a/vector/src/main/java/im/vector/riotx/core/dialogs/ExportKeysDialog.kt b/vector/src/main/java/im/vector/riotx/core/dialogs/ExportKeysDialog.kt
    index 25b2bb1004..fb320afded 100644
    --- a/vector/src/main/java/im/vector/riotx/core/dialogs/ExportKeysDialog.kt
    +++ b/vector/src/main/java/im/vector/riotx/core/dialogs/ExportKeysDialog.kt
    @@ -18,7 +18,6 @@ package im.vector.riotx.core.dialogs
     
     import android.app.Activity
     import android.text.Editable
    -import android.text.TextUtils
     import android.widget.Button
     import android.widget.ImageView
     import androidx.appcompat.app.AlertDialog
    @@ -45,15 +44,15 @@ class ExportKeysDialog {
             val textWatcher = object : SimpleTextWatcher() {
                 override fun afterTextChanged(s: Editable) {
                     when {
    -                    TextUtils.isEmpty(passPhrase1EditText.text)                          -> {
    +                    passPhrase1EditText.text.isNullOrEmpty()             -> {
                             exportButton.isEnabled = false
                             passPhrase2Til.error = null
                         }
    -                    TextUtils.equals(passPhrase1EditText.text, passPhrase2EditText.text) -> {
    +                    passPhrase1EditText.text == passPhrase2EditText.text -> {
                             exportButton.isEnabled = true
                             passPhrase2Til.error = null
                         }
    -                    else                                                                 -> {
    +                    else                                                 -> {
                             exportButton.isEnabled = false
                             passPhrase2Til.error = activity.getString(R.string.passphrase_passphrase_does_not_match)
                         }
    @@ -81,8 +80,7 @@ class ExportKeysDialog {
             }
         }
     
    -
         interface ExportKeyDialogListener {
             fun onPassphrase(passphrase: String)
         }
    -}
    \ No newline at end of file
    +}
    diff --git a/vector/src/main/java/im/vector/riotx/core/dialogs/DialogListItemHolder.kt b/vector/src/main/java/im/vector/riotx/core/dialogs/Extensions.kt
    similarity index 57%
    rename from vector/src/main/java/im/vector/riotx/core/dialogs/DialogListItemHolder.kt
    rename to vector/src/main/java/im/vector/riotx/core/dialogs/Extensions.kt
    index af8456ba1b..1b90e88864 100644
    --- a/vector/src/main/java/im/vector/riotx/core/dialogs/DialogListItemHolder.kt
    +++ b/vector/src/main/java/im/vector/riotx/core/dialogs/Extensions.kt
    @@ -5,7 +5,7 @@
      * 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
    + *     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,
    @@ -16,22 +16,12 @@
     
     package im.vector.riotx.core.dialogs
     
    -import android.view.View
    -import android.widget.ImageView
    -import android.widget.TextView
    -import butterknife.BindView
    -import butterknife.ButterKnife
    +import androidx.annotation.ColorRes
    +import androidx.appcompat.app.AlertDialog
    +import androidx.core.content.ContextCompat
     import im.vector.riotx.R
     
    -class DialogListItemHolder(view: View) {
    -
    -    @BindView(R.id.adapter_item_dialog_icon)
    -    lateinit var icon: ImageView
    -
    -    @BindView(R.id.adapter_item_dialog_text)
    -    lateinit var text: TextView
    -
    -    init {
    -        ButterKnife.bind(this, view)
    -    }
    -}
    \ No newline at end of file
    +fun AlertDialog.withColoredButton(whichButton: Int, @ColorRes color: Int = R.color.vector_error_color): AlertDialog {
    +    getButton(whichButton)?.setTextColor(ContextCompat.getColor(context, color))
    +    return this
    +}
    diff --git a/vector/src/main/java/im/vector/riotx/core/epoxy/EmptyItem.kt b/vector/src/main/java/im/vector/riotx/core/epoxy/EmptyItem.kt
    index 32d7183c1d..c0eb007952 100644
    --- a/vector/src/main/java/im/vector/riotx/core/epoxy/EmptyItem.kt
    +++ b/vector/src/main/java/im/vector/riotx/core/epoxy/EmptyItem.kt
    @@ -22,4 +22,4 @@ import im.vector.riotx.R
     @EpoxyModelClass(layout = R.layout.item_empty)
     abstract class EmptyItem : VectorEpoxyModel() {
         class Holder : VectorEpoxyHolder()
    -}
    \ No newline at end of file
    +}
    diff --git a/vector/src/main/java/im/vector/riotx/core/epoxy/ErrorWithRetryItem.kt b/vector/src/main/java/im/vector/riotx/core/epoxy/ErrorWithRetryItem.kt
    index 857de071e2..e6336e5753 100644
    --- a/vector/src/main/java/im/vector/riotx/core/epoxy/ErrorWithRetryItem.kt
    +++ b/vector/src/main/java/im/vector/riotx/core/epoxy/ErrorWithRetryItem.kt
    @@ -36,9 +36,8 @@ abstract class ErrorWithRetryItem : VectorEpoxyModel(
             holder.buttonView.setOnClickListener { listener?.invoke() }
         }
     
    -
         class Holder : VectorEpoxyHolder() {
             val textView by bind(R.id.itemErrorRetryText)
             val buttonView by bind