diff --git a/.github/ISSUE_TEMPLATE/release.yml b/.github/ISSUE_TEMPLATE/release.yml index c22b00e2e9..50a9cdf5fc 100644 --- a/.github/ISSUE_TEMPLATE/release.yml +++ b/.github/ISSUE_TEMPLATE/release.yml @@ -106,7 +106,7 @@ body: https://github.com/matrix-org/matrix-android-sdk2-sample - - [ ] Update the dependency to the new version of the SDK2. It can take some time for MavenCentral to make the librarie available. You can check status on https://repo1.maven.org/maven2/org/matrix/android/matrix-android-sdk2/ + - [ ] Update the dependency to the new version of the SDK2. It can take a few minutes for MavenCentral to make the library available. You can check status on https://repo1.maven.org/maven2/org/matrix/android/matrix-android-sdk2/ - [ ] Build and run the sample, you may have to fix some API break - [ ] Commit and push directly on `main` validations: diff --git a/.github/workflows/triage-labelled.yml b/.github/workflows/triage-labelled.yml index eeddf2e785..82d5931ce7 100644 --- a/.github/workflows/triage-labelled.yml +++ b/.github/workflows/triage-labelled.yml @@ -11,7 +11,6 @@ jobs: if: > contains(github.event.issue.labels.*.name, 'A-Maths') || contains(github.event.issue.labels.*.name, 'A-Message-Pinning') || - contains(github.event.issue.labels.*.name, 'A-Threads') || contains(github.event.issue.labels.*.name, 'A-Polls') || contains(github.event.issue.labels.*.name, 'A-Location-Sharing') || contains(github.event.issue.labels.*.name, 'A-Message-Bubbles') || @@ -252,3 +251,30 @@ jobs: env: PROJECT_ID: "PN_kwDOAM0swc4AArk0" GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }} + + move_element_x_issues: + name: ElementX issues to ElementX project board + runs-on: ubuntu-latest + # Skip in forks + if: > + github.repository == 'vector-im/element-android' && + (contains(github.event.issue.labels.*.name, 'Z-ElementX-Alpha') || + contains(github.event.issue.labels.*.name, 'Z-ElementX-Beta') || + contains(github.event.issue.labels.*.name, 'Z-ElementX')) + steps: + - uses: octokit/graphql-action@v2.x + with: + headers: '{"GraphQL-Features": "projects_next_graphql"}' + query: | + mutation add_to_project($projectid:ID!,$contentid:ID!) { + addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) { + projectNextItem { + id + } + } + } + projectid: ${{ env.PROJECT_ID }} + contentid: ${{ github.event.issue.node_id }} + env: + PROJECT_ID: "PN_kwDOAM0swc4ABTXY" + GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }} diff --git a/.github/workflows/triage-move-review-requests.yml b/.github/workflows/triage-move-review-requests.yml index 75738a53a9..61f1f114dd 100644 --- a/.github/workflows/triage-move-review-requests.yml +++ b/.github/workflows/triage-move-review-requests.yml @@ -7,6 +7,8 @@ jobs: add_design_pr_to_project: name: Move PRs asking for design review to the design board runs-on: ubuntu-latest + # Skip in forks + if: github.repository == 'vector-im/element-android' steps: - uses: octokit/graphql-action@v2.x id: find_team_members @@ -74,6 +76,8 @@ jobs: add_product_pr_to_project: name: Move PRs asking for product review to the product board runs-on: ubuntu-latest + # Skip in forks + if: github.repository == 'vector-im/element-android' steps: - uses: octokit/graphql-action@v2.x id: find_team_members diff --git a/.github/workflows/update-gradle-wrapper.yml b/.github/workflows/update-gradle-wrapper.yml index 1cbf29cc8d..63aaae15a5 100644 --- a/.github/workflows/update-gradle-wrapper.yml +++ b/.github/workflows/update-gradle-wrapper.yml @@ -13,6 +13,8 @@ jobs: - name: Update Gradle Wrapper uses: gradle-update/update-gradle-wrapper-action@v1 + # Skip in forks + if: github.repository == 'vector-im/element-android' with: repo-token: ${{ secrets.GITHUB_TOKEN }} target-branch: develop diff --git a/CHANGES.md b/CHANGES.md index 4728994d77..f952ec952a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,11 @@ +Changes in Element 1.4.13 (2022-04-26) +====================================== + +Bugfixes 🐛 +---------- + - Fix UI freeze observed after each incremental sync ([#5835](https://github.com/vector-im/element-android/issues/5835)) + + Changes in Element v1.4.12 (2022-04-20) ======================================= diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 053931cac5..52ccf47e6a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -124,7 +124,9 @@ As a general rule, please never edit or add or remove translations to the projec #### Adding new string -When adding new string resources, please only add new entries in file `value/strings.xml`. Translations will be added later by the community of translators using Weblate. +When adding new string resources, please only add new entries in the file `value/strings.xml`. Translations will be added later by the community of translators using Weblate. + +The file `value/strings.xml` must only contain American English (U. S. English) values, as this is the default language of the Android operating system. So for instance, please use "color" instead of "colour". Element Android will still use the language set on the system by the user, like any other Android applications which provide translations. The system language can be any other English language variants, or any other languages. Note that this is also possible to override the system language using the Element Android in-app language settings. New strings can be added anywhere in the file `value/strings.xml`, not necessarily at the end of the file. Generally, it's even better to add the new strings in some dedicated section per feature, and not at the end of the file, to avoid merge conflict between 2 PR adding strings at the end of the same file. diff --git a/build.gradle b/build.gradle index 1ff1da7427..1d86f482da 100644 --- a/build.gradle +++ b/build.gradle @@ -21,8 +21,8 @@ buildscript { classpath 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.3' classpath 'com.google.android.gms:oss-licenses-plugin:0.10.5' classpath "com.likethesalad.android:stem-plugin:2.0.0" - classpath 'org.owasp:dependency-check-gradle:7.0.4.1' - classpath "org.jetbrains.dokka:dokka-gradle-plugin:1.6.20" + classpath 'org.owasp:dependency-check-gradle:7.1.0.1' + classpath "org.jetbrains.dokka:dokka-gradle-plugin:1.6.21" // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } @@ -30,7 +30,7 @@ buildscript { // ktlint Plugin plugins { - id "org.jlleitschuh.gradle.ktlint" version "10.2.1" + id "org.jlleitschuh.gradle.ktlint" version "10.3.0" } // https://github.com/jeremylong/DependencyCheck diff --git a/changelog.d/5421.bugfix b/changelog.d/5421.bugfix new file mode 100644 index 0000000000..2f9a1c0b1c --- /dev/null +++ b/changelog.d/5421.bugfix @@ -0,0 +1 @@ +Fixes crash when accepting or receiving VOIP calls diff --git a/changelog.d/5592.bugfix b/changelog.d/5592.bugfix new file mode 100644 index 0000000000..f0df3dc646 --- /dev/null +++ b/changelog.d/5592.bugfix @@ -0,0 +1 @@ +Improve/fix crashes on messages decryption diff --git a/changelog.d/5721.bugfix b/changelog.d/5721.bugfix new file mode 100644 index 0000000000..8b752b43a9 --- /dev/null +++ b/changelog.d/5721.bugfix @@ -0,0 +1 @@ +Improving deactivation experience along with a crash fix \ No newline at end of file diff --git a/changelog.d/5783.wip b/changelog.d/5783.wip new file mode 100644 index 0000000000..e306c0f217 --- /dev/null +++ b/changelog.d/5783.wip @@ -0,0 +1 @@ +Reorders the registration steps to prioritise email, then terms for the FTUE onboarding diff --git a/changelog.d/5812.sdk b/changelog.d/5812.sdk new file mode 100644 index 0000000000..5ddd8cfac1 --- /dev/null +++ b/changelog.d/5812.sdk @@ -0,0 +1 @@ +Move package `org.matrix.android.sdk.api.pushrules` to `org.matrix.android.sdk.api.session.pushrules` diff --git a/changelog.d/5814.feature b/changelog.d/5814.feature new file mode 100644 index 0000000000..c892702486 --- /dev/null +++ b/changelog.d/5814.feature @@ -0,0 +1 @@ +Live location sharing: updating beacon state event content structure diff --git a/changelog.d/5816.sdk b/changelog.d/5816.sdk new file mode 100644 index 0000000000..17233c66e5 --- /dev/null +++ b/changelog.d/5816.sdk @@ -0,0 +1,2 @@ +Some `Session` apis are now available by requesting the service first. For instance `Session.updateAvatar(...)` is now `Session.profileService().updateAvatar(...)` +The shortcut `Room.search()` has been removed, you have to use `Session.searchService().search()` diff --git a/changelog.d/5826.bugfix b/changelog.d/5826.bugfix new file mode 100644 index 0000000000..2735568f73 --- /dev/null +++ b/changelog.d/5826.bugfix @@ -0,0 +1 @@ +Adds missing suggested tag for rooms in Explore Space diff --git a/changelog.d/5832.misc b/changelog.d/5832.misc new file mode 100644 index 0000000000..ace9dff5d4 --- /dev/null +++ b/changelog.d/5832.misc @@ -0,0 +1 @@ +Add a GH workflow to push ElementX issues to the global board. \ No newline at end of file diff --git a/changelog.d/5836.doc b/changelog.d/5836.doc new file mode 100644 index 0000000000..42073d66ef --- /dev/null +++ b/changelog.d/5836.doc @@ -0,0 +1 @@ +Update the PR process doc with 2 reviewers and a new reviewer team. \ No newline at end of file diff --git a/changelog.d/5847.bugfix b/changelog.d/5847.bugfix new file mode 100644 index 0000000000..acd13dec9a --- /dev/null +++ b/changelog.d/5847.bugfix @@ -0,0 +1 @@ +Fixes missing call icons when threads are enabled diff --git a/changelog.d/5854.doc b/changelog.d/5854.doc new file mode 100644 index 0000000000..38a1c756af --- /dev/null +++ b/changelog.d/5854.doc @@ -0,0 +1 @@ +Improve documentation of the project and of the SDK diff --git a/changelog.d/5855.sdk b/changelog.d/5855.sdk new file mode 100644 index 0000000000..bad5a11398 --- /dev/null +++ b/changelog.d/5855.sdk @@ -0,0 +1 @@ +- Add return type to RoomApi.sendStateEvent() to retrieve the created event id diff --git a/changelog.d/5858.sdk b/changelog.d/5858.sdk new file mode 100644 index 0000000000..9f2e7ef0f2 --- /dev/null +++ b/changelog.d/5858.sdk @@ -0,0 +1 @@ +`Room` apis are now available by requesting the service first. For instance `Room.updateAvatar(...)` is now `Room.stateService().updateAvatar(...)` diff --git a/changelog.d/5862.wip b/changelog.d/5862.wip new file mode 100644 index 0000000000..303a054c5e --- /dev/null +++ b/changelog.d/5862.wip @@ -0,0 +1 @@ +[Live location sharing] Improve aggregation process of events diff --git a/changelog.d/5871.bugfix b/changelog.d/5871.bugfix new file mode 100644 index 0000000000..b223ddd141 --- /dev/null +++ b/changelog.d/5871.bugfix @@ -0,0 +1 @@ +Fix UX freezing when creating secure backup diff --git a/changelog.d/5872.misc b/changelog.d/5872.misc new file mode 100644 index 0000000000..1e15229800 --- /dev/null +++ b/changelog.d/5872.misc @@ -0,0 +1 @@ +Faster Olm decrypt when there is a lot of existing sessions diff --git a/changelog.d/5874.bugfix b/changelog.d/5874.bugfix new file mode 100644 index 0000000000..a0f700bed5 --- /dev/null +++ b/changelog.d/5874.bugfix @@ -0,0 +1 @@ +Fixes sign in via other requiring homeserver registration to be enabled diff --git a/changelog.d/5886.bugfix b/changelog.d/5886.bugfix new file mode 100644 index 0000000000..c4239e5c3a --- /dev/null +++ b/changelog.d/5886.bugfix @@ -0,0 +1 @@ +Fix UISIDetector grace period bug diff --git a/changelog.d/5890.sdk b/changelog.d/5890.sdk new file mode 100644 index 0000000000..0d5e8d783d --- /dev/null +++ b/changelog.d/5890.sdk @@ -0,0 +1 @@ +Remove unecessary field `eventId` from `EventAnnotationsSummary` and `ReferencesAggregatedSummary` diff --git a/changelog.d/5924.bugfix b/changelog.d/5924.bugfix new file mode 100644 index 0000000000..8a159211fe --- /dev/null +++ b/changelog.d/5924.bugfix @@ -0,0 +1 @@ +Fix a crash with space invitations in the space list, and do not display space invitation twice. diff --git a/changelog.d/5925.bugfix b/changelog.d/5925.bugfix new file mode 100644 index 0000000000..eff0c17a5c --- /dev/null +++ b/changelog.d/5925.bugfix @@ -0,0 +1 @@ +Fixes crash on android api 21/22 devices when opening messages due to Konfetti library diff --git a/dependencies_groups.gradle b/dependencies_groups.gradle index 2c3f6a0219..8422e05930 100644 --- a/dependencies_groups.gradle +++ b/dependencies_groups.gradle @@ -164,6 +164,7 @@ ext.groups = [ 'org.codehaus.woodstox', 'org.eclipse.ee4j', 'org.ec4j.core', + 'org.freemarker', 'org.glassfish.jaxb', 'org.hamcrest', 'org.jacoco', diff --git a/docs/pull_request.md b/docs/pull_request.md index b4dd0bd209..4775f292ee 100644 --- a/docs/pull_request.md +++ b/docs/pull_request.md @@ -32,14 +32,15 @@ Also, draft PR should not stay indefinitely in this state. It may be removed if ##### PR Review Assignment -We use automatic assignment for PR reviews. A PR is automatically routed by GitHub to a team member using the round robin algorithm. The process is the following: +We use automatic assignment for PR reviews. A PR is automatically routed by GitHub to 2 team members using the round robin algorithm. The process is the following: -- The PR creator assigns the [element-android](https://github.com/orgs/vector-im/teams/element-android) team as a reviewer. They can skip this process and assign directly a specific member if they think they should take a look at it. -- GitHub automatically assigns one reviewer. If the chosen reviewer is not available (holiday, etc.), remove them and set again the team, GitHub will select another reviewer. -- The reviewer gets a notification to make the review: they review the code following the good practice (see the rest of this document). +- The PR creator can assign specific people if they have another Android developer in their team or they think a specific reviewer should take a look at the PR. +- If there are missing reviewers, the PR creator assigns the [element-android-reviewers](https://github.com/orgs/vector-im/teams/element-android-reviewers) team as a reviewer. +- GitHub automatically assigns other reviewers. If one of the chosen reviewers is not available (holiday, etc.), remove them and set again the team, GitHub will select another reviewer. +- Reviewers get a notification to make the review: they review the code following the good practice (see the rest of this document). - After making their own review, if they feel not confident enough, they can ask another person for a full review, or they can tag someone within a PR comment to check specific lines. -For PRs coming from the community, the issue wrangler can assign either the team [element-android](https://github.com/orgs/vector-im/teams/element-android) or any member directly. +For PRs coming from the community, the issue wrangler can assign either the team [element-android-reviewers](https://github.com/orgs/vector-im/teams/element-android-reviewers) or any members directly. ##### PR review time diff --git a/fastlane/metadata/android/en-US/changelogs/40104130.txt b/fastlane/metadata/android/en-US/changelogs/40104130.txt new file mode 100644 index 0000000000..ea188c101c --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/40104130.txt @@ -0,0 +1,2 @@ +Main changes in this version: Allows users to appear offline and adds an audio player for audio attachments +Full changelog: https://github.com/vector-im/element-android/releases diff --git a/matrix-sdk-android-flow/src/main/java/org/matrix/android/sdk/flow/FlowRoom.kt b/matrix-sdk-android-flow/src/main/java/org/matrix/android/sdk/flow/FlowRoom.kt index 0f0153bc23..90546756b8 100644 --- a/matrix-sdk-android-flow/src/main/java/org/matrix/android/sdk/flow/FlowRoom.kt +++ b/matrix-sdk-android-flow/src/main/java/org/matrix/android/sdk/flow/FlowRoom.kt @@ -21,6 +21,8 @@ import kotlinx.coroutines.flow.Flow import org.matrix.android.sdk.api.query.QueryStringValue import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.room.Room +import org.matrix.android.sdk.api.session.room.getStateEvent +import org.matrix.android.sdk.api.session.room.getTimelineEvent import org.matrix.android.sdk.api.session.room.members.RoomMemberQueryParams import org.matrix.android.sdk.api.session.room.model.EventAnnotationsSummary import org.matrix.android.sdk.api.session.room.model.ReadReceipt @@ -45,81 +47,81 @@ class FlowRoom(private val room: Room) { } fun liveRoomMembers(queryParams: RoomMemberQueryParams): Flow> { - return room.getRoomMembersLive(queryParams).asFlow() + return room.membershipService().getRoomMembersLive(queryParams).asFlow() .startWith(room.coroutineDispatchers.io) { - room.getRoomMembers(queryParams) + room.membershipService().getRoomMembers(queryParams) } } fun liveAnnotationSummary(eventId: String): Flow> { - return room.getEventAnnotationsSummaryLive(eventId).asFlow() + return room.relationService().getEventAnnotationsSummaryLive(eventId).asFlow() .startWith(room.coroutineDispatchers.io) { - room.getEventAnnotationsSummary(eventId).toOptional() + room.relationService().getEventAnnotationsSummary(eventId).toOptional() } } fun liveTimelineEvent(eventId: String): Flow> { - return room.getTimelineEventLive(eventId).asFlow() + return room.timelineService().getTimelineEventLive(eventId).asFlow() .startWith(room.coroutineDispatchers.io) { room.getTimelineEvent(eventId).toOptional() } } fun liveStateEvent(eventType: String, stateKey: QueryStringValue): Flow> { - return room.getStateEventLive(eventType, stateKey).asFlow() + return room.stateService().getStateEventLive(eventType, stateKey).asFlow() .startWith(room.coroutineDispatchers.io) { room.getStateEvent(eventType, stateKey).toOptional() } } fun liveStateEvents(eventTypes: Set): Flow> { - return room.getStateEventsLive(eventTypes).asFlow() + return room.stateService().getStateEventsLive(eventTypes).asFlow() .startWith(room.coroutineDispatchers.io) { - room.getStateEvents(eventTypes) + room.stateService().getStateEvents(eventTypes) } } fun liveReadMarker(): Flow> { - return room.getReadMarkerLive().asFlow() + return room.readService().getReadMarkerLive().asFlow() } fun liveReadReceipt(): Flow> { - return room.getMyReadReceiptLive().asFlow() + return room.readService().getMyReadReceiptLive().asFlow() } fun liveEventReadReceipts(eventId: String): Flow> { - return room.getEventReadReceiptsLive(eventId).asFlow() + return room.readService().getEventReadReceiptsLive(eventId).asFlow() } fun liveDraft(): Flow> { - return room.getDraftLive().asFlow() + return room.draftService().getDraftLive().asFlow() .startWith(room.coroutineDispatchers.io) { - room.getDraft().toOptional() + room.draftService().getDraft().toOptional() } } fun liveNotificationState(): Flow { - return room.getLiveRoomNotificationState().asFlow() + return room.roomPushRuleService().getLiveRoomNotificationState().asFlow() } fun liveThreadSummaries(): Flow> { - return room.getAllThreadSummariesLive().asFlow() + return room.threadsService().getAllThreadSummariesLive().asFlow() .startWith(room.coroutineDispatchers.io) { - room.getAllThreadSummaries() + room.threadsService().getAllThreadSummaries() } } fun liveThreadList(): Flow> { - return room.getAllThreadsLive().asFlow() + return room.threadsLocalService().getAllThreadsLive().asFlow() .startWith(room.coroutineDispatchers.io) { - room.getAllThreads() + room.threadsLocalService().getAllThreads() } } fun liveLocalUnreadThreadList(): Flow> { - return room.getMarkedThreadNotificationsLive().asFlow() + return room.threadsLocalService().getMarkedThreadNotificationsLive().asFlow() .startWith(room.coroutineDispatchers.io) { - room.getMarkedThreadNotifications() + room.threadsLocalService().getMarkedThreadNotifications() } } } diff --git a/matrix-sdk-android-flow/src/main/java/org/matrix/android/sdk/flow/FlowSession.kt b/matrix-sdk-android-flow/src/main/java/org/matrix/android/sdk/flow/FlowSession.kt index 18753f0705..9f260858f6 100644 --- a/matrix-sdk-android-flow/src/main/java/org/matrix/android/sdk/flow/FlowSession.kt +++ b/matrix-sdk-android-flow/src/main/java/org/matrix/android/sdk/flow/FlowSession.kt @@ -46,16 +46,16 @@ import org.matrix.android.sdk.api.util.toOptional class FlowSession(private val session: Session) { fun liveRoomSummaries(queryParams: RoomSummaryQueryParams, sortOrder: RoomSortOrder = RoomSortOrder.NONE): Flow> { - return session.getRoomSummariesLive(queryParams, sortOrder).asFlow() + return session.roomService().getRoomSummariesLive(queryParams, sortOrder).asFlow() .startWith(session.coroutineDispatchers.io) { - session.getRoomSummaries(queryParams, sortOrder) + session.roomService().getRoomSummaries(queryParams, sortOrder) } } fun liveGroupSummaries(queryParams: GroupSummaryQueryParams): Flow> { - return session.getGroupSummariesLive(queryParams).asFlow() + return session.groupService().getGroupSummariesLive(queryParams).asFlow() .startWith(session.coroutineDispatchers.io) { - session.getGroupSummaries(queryParams) + session.groupService().getGroupSummaries(queryParams) } } @@ -67,9 +67,9 @@ class FlowSession(private val session: Session) { } fun liveBreadcrumbs(queryParams: RoomSummaryQueryParams): Flow> { - return session.getBreadcrumbsLive(queryParams).asFlow() + return session.roomService().getBreadcrumbsLive(queryParams).asFlow() .startWith(session.coroutineDispatchers.io) { - session.getBreadcrumbs(queryParams) + session.roomService().getBreadcrumbs(queryParams) } } @@ -85,43 +85,47 @@ class FlowSession(private val session: Session) { } fun livePushers(): Flow> { - return session.getPushersLive().asFlow() + return session.pushersService().getPushersLive().asFlow() } fun liveUser(userId: String): Flow> { - return session.getUserLive(userId).asFlow() + return session.userService().getUserLive(userId).asFlow() .startWith(session.coroutineDispatchers.io) { - session.getUser(userId).toOptional() + session.userService().getUser(userId).toOptional() } } fun liveRoomMember(userId: String, roomId: String): Flow> { - return session.getRoomMemberLive(userId, roomId).asFlow() + return session.roomService().getRoomMemberLive(userId, roomId).asFlow() .startWith(session.coroutineDispatchers.io) { - session.getRoomMember(userId, roomId).toOptional() + session.roomService().getRoomMember(userId, roomId).toOptional() } } fun liveUsers(): Flow> { - return session.getUsersLive().asFlow() + return session.userService().getUsersLive().asFlow() } fun liveIgnoredUsers(): Flow> { - return session.getIgnoredUsersLive().asFlow() + return session.userService().getIgnoredUsersLive().asFlow() } fun livePagedUsers(filter: String? = null, excludedUserIds: Set? = null): Flow> { - return session.getPagedUsersLive(filter, excludedUserIds).asFlow() + return session.userService().getPagedUsersLive(filter, excludedUserIds).asFlow() } fun liveThreePIds(refreshData: Boolean): Flow> { - return session.getThreePidsLive(refreshData).asFlow() - .startWith(session.coroutineDispatchers.io) { session.getThreePids() } + return session.profileService().getThreePidsLive(refreshData).asFlow() + .startWith(session.coroutineDispatchers.io) { + session.profileService().getThreePids() + } } fun livePendingThreePIds(): Flow> { - return session.getPendingThreePidsLive().asFlow() - .startWith(session.coroutineDispatchers.io) { session.getPendingThreePids() } + return session.profileService().getPendingThreePidsLive().asFlow() + .startWith(session.coroutineDispatchers.io) { + session.profileService().getPendingThreePids() + } } fun liveUserCryptoDevices(userId: String): Flow> { @@ -179,7 +183,7 @@ class FlowSession(private val session: Session) { } fun liveRoomChangeMembershipState(): Flow> { - return session.getChangeMembershipsLive().asFlow() + return session.roomService().getChangeMembershipsLive().asFlow() } } diff --git a/matrix-sdk-android/build.gradle b/matrix-sdk-android/build.gradle index 3ee20b88c2..2aab8510ce 100644 --- a/matrix-sdk-android/build.gradle +++ b/matrix-sdk-android/build.gradle @@ -14,6 +14,27 @@ buildscript { } } +dokkaHtml { + dokkaSourceSets { + configureEach { + // Emit warnings about not documented members. + reportUndocumented.set(true) + // Suppress legacy Riot's packages. + perPackageOption { + matchingRegex.set("org.matrix.android.sdk.internal.legacy.riot") + suppress.set(true) + } + perPackageOption { + matchingRegex.set("org.matrix.androidsdk.crypto.data") + suppress.set(true) + } + // List of files with module and package documentation + // https://kotlinlang.org/docs/reference/kotlin-doc.html#module-and-package-documentation + includes.from("./docs/modules.md", "./docs/packages.md") + } + } +} + android { testOptions.unitTests.includeAndroidResources = true diff --git a/matrix-sdk-android/docs/modules.md b/matrix-sdk-android/docs/modules.md new file mode 100644 index 0000000000..edf5af64d0 --- /dev/null +++ b/matrix-sdk-android/docs/modules.md @@ -0,0 +1,18 @@ +# Module matrix-sdk-android + +## Welcome to the matrix-sdk-android documentation! + +This pages list the complete API that this SDK is exposing to a client application. + +*We are still building the documentation, so everything is not documented yet.* + +A few entry points: + +- **Matrix**: The app will have to create and manage a Matrix object. +- From this **Matrix** object, you will be able to get various services, including the **AuthenticationService**. +- With this **AuthenticationService** you will be able to get an existing **Session**, or create one using a **LoginWizard** or a **RegistrationWizard**, which will finally give you a **Session**. +- From the **Session**, you will be able to retrieve many Services, including the **RoomService**. +- From the **RoomService**, you will be able to list the rooms, create a **Room**, and get a specific **Room**. +- And from a **Room**, you will be able to do many things, including get a **Timeline**, send messages, etc. + +Please read the whole documentation to learn more! diff --git a/matrix-sdk-android/docs/packages.md b/matrix-sdk-android/docs/packages.md new file mode 100644 index 0000000000..ae7bee1b4e --- /dev/null +++ b/matrix-sdk-android/docs/packages.md @@ -0,0 +1,3 @@ +# Package org.matrix.android.sdk.api + +This is the root package of the API exposed by this SDK. diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/ChangePasswordTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/ChangePasswordTest.kt index 933074cdce..6d740c5a34 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/ChangePasswordTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/ChangePasswordTest.kt @@ -46,7 +46,7 @@ class ChangePasswordTest : InstrumentedTest { // Change password commonTestHelper.runBlockingTest { - session.changePassword(TestConstants.PASSWORD, NEW_PASSWORD) + session.accountService().changePassword(TestConstants.PASSWORD, NEW_PASSWORD) } // Try to login with the previous password, it will fail diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/DeactivateAccountTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/DeactivateAccountTest.kt index f8d108fb73..52dbfc7155 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/DeactivateAccountTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/DeactivateAccountTest.kt @@ -47,7 +47,7 @@ class DeactivateAccountTest : InstrumentedTest { // Deactivate the account commonTestHelper.runBlockingTest { - session.deactivateAccount( + session.accountService().deactivateAccount( eraseAllData = false, userInteractiveAuthInterceptor = object : UserInteractiveAuthInterceptor { override fun performStage(flowResponse: RegistrationFlowResponse, errCode: String?, promise: Continuation) { diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CommonTestHelper.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CommonTestHelper.kt index ac4ccf56d1..54d02d226e 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CommonTestHelper.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CommonTestHelper.kt @@ -145,7 +145,7 @@ class CommonTestHelper(context: Context) { * @param nbOfMessages the number of time the message will be sent */ fun sendTextMessage(room: Room, message: String, nbOfMessages: Int, timeout: Long = TestConstants.timeOutMillis): List { - val timeline = room.createTimeline(null, TimelineSettings(10)) + val timeline = room.timelineService().createTimeline(null, TimelineSettings(10)) timeline.start() val sentEvents = sendTextMessagesBatched(timeline, room, message, nbOfMessages, timeout) timeline.dispose() @@ -165,11 +165,11 @@ class CommonTestHelper(context: Context) { .forEach { batchedMessages -> batchedMessages.forEach { formattedMessage -> if (rootThreadEventId != null) { - room.replyInThread( + room.relationService().replyInThread( rootThreadEventId = rootThreadEventId, replyInThreadText = formattedMessage) } else { - room.sendTextMessage(formattedMessage) + room.sendService().sendTextMessage(formattedMessage) } } waitWithLatch(timeout) { latch -> @@ -214,7 +214,7 @@ class CommonTestHelper(context: Context) { numberOfMessages: Int, rootThreadEventId: String, timeout: Long = TestConstants.timeOutMillis): List { - val timeline = room.createTimeline(null, TimelineSettings(10)) + val timeline = room.timelineService().createTimeline(null, TimelineSettings(10)) timeline.start() val sentEvents = sendTextMessagesBatched(timeline, room, message, numberOfMessages, timeout, rootThreadEventId) timeline.dispose() @@ -431,7 +431,7 @@ class CommonTestHelper(context: Context) { fun signOutAndClose(session: Session) { runBlockingTest(timeout = 60_000) { - session.signOut(true) + session.signOutService().signOut(true) } // no need signout will close // session.close() diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CryptoTestHelper.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CryptoTestHelper.kt index e3ab1a4921..058b1f7933 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CryptoTestHelper.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CryptoTestHelper.kt @@ -40,6 +40,7 @@ import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxStat import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.toContent +import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.room.Room import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.model.RoomSummary @@ -64,12 +65,12 @@ class CryptoTestHelper(private val testHelper: CommonTestHelper) { val aliceSession = testHelper.createAccount(TestConstants.USER_ALICE, defaultSessionParams) val roomId = testHelper.runBlockingTest { - aliceSession.createRoom(CreateRoomParams().apply { name = "MyRoom" }) + aliceSession.roomService().createRoom(CreateRoomParams().apply { name = "MyRoom" }) } if (encryptedRoom) { testHelper.waitWithLatch { latch -> val room = aliceSession.getRoom(roomId)!! - room.enableEncryption() + room.roomCryptoService().enableEncryption() val roomSummaryLive = room.getRoomSummaryLive() val roomSummaryObserver = object : Observer> { override fun onChanged(roomSummary: Optional) { @@ -98,7 +99,7 @@ class CryptoTestHelper(private val testHelper: CommonTestHelper) { val bobSession = testHelper.createAccount(TestConstants.USER_BOB, defaultSessionParams) testHelper.waitWithLatch { latch -> - val bobRoomSummariesLive = bobSession.getRoomSummariesLive(roomSummaryQueryParams { }) + val bobRoomSummariesLive = bobSession.roomService().getRoomSummariesLive(roomSummaryQueryParams { }) val newRoomObserver = object : Observer> { override fun onChanged(t: List?) { if (t?.isNotEmpty() == true) { @@ -108,14 +109,15 @@ class CryptoTestHelper(private val testHelper: CommonTestHelper) { } } bobRoomSummariesLive.observeForever(newRoomObserver) - aliceRoom.invite(bobSession.myUserId) + aliceRoom.membershipService().invite(bobSession.myUserId) } testHelper.waitWithLatch { latch -> - val bobRoomSummariesLive = bobSession.getRoomSummariesLive(roomSummaryQueryParams { }) + val bobRoomSummariesLive = bobSession.roomService().getRoomSummariesLive(roomSummaryQueryParams { }) val roomJoinedObserver = object : Observer> { override fun onChanged(t: List?) { if (bobSession.getRoom(aliceRoomId) + ?.membershipService() ?.getRoomMember(bobSession.myUserId) ?.membership == Membership.JOIN) { bobRoomSummariesLive.removeObserver(this) @@ -124,7 +126,7 @@ class CryptoTestHelper(private val testHelper: CommonTestHelper) { } } bobRoomSummariesLive.observeForever(roomJoinedObserver) - bobSession.joinRoom(aliceRoomId) + bobSession.roomService().joinRoom(aliceRoomId) } // Ensure bob can send messages to the room // val roomFromBobPOV = bobSession.getRoom(aliceRoomId)!! @@ -160,11 +162,11 @@ class CryptoTestHelper(private val testHelper: CommonTestHelper) { val samSession = testHelper.createAccount(TestConstants.USER_SAM, defaultSessionParams) testHelper.runBlockingTest { - room.invite(samSession.myUserId, null) + room.membershipService().invite(samSession.myUserId, null) } testHelper.runBlockingTest { - samSession.joinRoom(room.roomId, null, emptyList()) + samSession.roomService().joinRoom(room.roomId, null, emptyList()) } return samSession @@ -242,8 +244,8 @@ class CryptoTestHelper(private val testHelper: CommonTestHelper) { fun createDM(alice: Session, bob: Session): String { var roomId: String = "" testHelper.waitWithLatch { latch -> - roomId = alice.createDirectRoom(bob.myUserId) - val bobRoomSummariesLive = bob.getRoomSummariesLive(roomSummaryQueryParams { }) + roomId = alice.roomService().createDirectRoom(bob.myUserId) + val bobRoomSummariesLive = bob.roomService().getRoomSummariesLive(roomSummaryQueryParams { }) val newRoomObserver = object : Observer> { override fun onChanged(t: List?) { if (t?.any { it.roomId == roomId }.orFalse()) { @@ -256,10 +258,11 @@ class CryptoTestHelper(private val testHelper: CommonTestHelper) { } testHelper.waitWithLatch { latch -> - val bobRoomSummariesLive = bob.getRoomSummariesLive(roomSummaryQueryParams { }) + val bobRoomSummariesLive = bob.roomService().getRoomSummariesLive(roomSummaryQueryParams { }) val newRoomObserver = object : Observer> { override fun onChanged(t: List?) { if (bob.getRoom(roomId) + ?.membershipService() ?.getRoomMember(bob.myUserId) ?.membership == Membership.JOIN) { bobRoomSummariesLive.removeObserver(this) @@ -268,7 +271,7 @@ class CryptoTestHelper(private val testHelper: CommonTestHelper) { } } bobRoomSummariesLive.observeForever(newRoomObserver) - bob.joinRoom(roomId) + bob.roomService().joinRoom(roomId) } return roomId @@ -367,20 +370,20 @@ class CryptoTestHelper(private val testHelper: CommonTestHelper) { aliceSession.cryptoService().setWarnOnUnknownDevices(false) val roomId = testHelper.runBlockingTest { - aliceSession.createRoom(CreateRoomParams().apply { name = "MyRoom" }) + aliceSession.roomService().createRoom(CreateRoomParams().apply { name = "MyRoom" }) } val room = aliceSession.getRoom(roomId)!! testHelper.runBlockingTest { - room.enableEncryption() + room.roomCryptoService().enableEncryption() } val sessions = mutableListOf(aliceSession) for (index in 1 until numberOfMembers) { val session = testHelper.createAccount("User_$index", defaultSessionParams) - testHelper.runBlockingTest(timeout = 600_000) { room.invite(session.myUserId, null) } + testHelper.runBlockingTest(timeout = 600_000) { room.membershipService().invite(session.myUserId, null) } println("TEST -> " + session.myUserId + " invited") - testHelper.runBlockingTest { session.joinRoom(room.roomId, null, emptyList()) } + testHelper.runBlockingTest { session.roomService().joinRoom(room.roomId, null, emptyList()) } println("TEST -> " + session.myUserId + " joined") sessions.add(session) } diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/E2eeSanityTests.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/E2eeSanityTests.kt index 3884683151..88d99f12e0 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/E2eeSanityTests.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/E2eeSanityTests.kt @@ -38,8 +38,11 @@ import org.matrix.android.sdk.api.session.crypto.model.OlmDecryptionResult import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.content.EncryptedEventContent import org.matrix.android.sdk.api.session.events.model.toModel +import org.matrix.android.sdk.api.session.getRoom +import org.matrix.android.sdk.api.session.getRoomSummary import org.matrix.android.sdk.api.session.room.Room import org.matrix.android.sdk.api.session.room.failure.JoinRoomFailure +import org.matrix.android.sdk.api.session.room.getTimelineEvent import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.model.message.MessageContent import org.matrix.android.sdk.api.session.room.send.SendState @@ -86,7 +89,7 @@ class E2eeSanityTests : InstrumentedTest { otherAccounts.forEach { testHelper.runBlockingTest { Log.v("#E2E TEST", "Alice invites ${it.myUserId}") - aliceRoomPOV.invite(it.myUserId) + aliceRoomPOV.membershipService().invite(it.myUserId) } } @@ -128,7 +131,7 @@ class E2eeSanityTests : InstrumentedTest { newAccount.forEach { testHelper.runBlockingTest { Log.v("#E2E TEST", "Alice invites ${it.myUserId}") - aliceRoomPOV.invite(it.myUserId) + aliceRoomPOV.membershipService().invite(it.myUserId) } } @@ -523,10 +526,10 @@ class E2eeSanityTests : InstrumentedTest { } private fun sendMessageInRoom(aliceRoomPOV: Room, text: String): String? { - aliceRoomPOV.sendTextMessage(text) + aliceRoomPOV.sendService().sendTextMessage(text) var sentEventId: String? = null testHelper.waitWithLatch(4 * TestConstants.timeOutMillis) { latch -> - val timeline = aliceRoomPOV.createTimeline(null, TimelineSettings(60)) + val timeline = aliceRoomPOV.timelineService().createTimeline(null, TimelineSettings(60)) timeline.start() testHelper.retryPeriodicallyWithLatch(latch) { @@ -551,7 +554,7 @@ class E2eeSanityTests : InstrumentedTest { testHelper.waitWithLatch { latch -> testHelper.retryPeriodicallyWithLatch(latch) { otherAccounts.map { - aliceSession.getRoomMember(it.myUserId, e2eRoomID)?.membership + aliceSession.roomService().getRoomMember(it.myUserId, e2eRoomID)?.membership }.all { it == Membership.JOIN } @@ -574,7 +577,7 @@ class E2eeSanityTests : InstrumentedTest { testHelper.runBlockingTest(60_000) { Log.v("#E2E TEST", "${otherSession.myUserId} tries to join room $e2eRoomID") try { - otherSession.joinRoom(e2eRoomID) + otherSession.roomService().joinRoom(e2eRoomID) } catch (ex: JoinRoomFailure.JoinedWithTimeout) { // it's ok we will wait after } diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/PreShareKeysTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/PreShareKeysTest.kt index aa9f09314f..8a1edec5e3 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/PreShareKeysTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/PreShareKeysTest.kt @@ -29,6 +29,8 @@ import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.content.EncryptedEventContent import org.matrix.android.sdk.api.session.events.model.content.RoomKeyContent import org.matrix.android.sdk.api.session.events.model.toModel +import org.matrix.android.sdk.api.session.getRoom +import org.matrix.android.sdk.api.session.room.getTimelineEvent import org.matrix.android.sdk.common.CommonTestHelper import org.matrix.android.sdk.common.CryptoTestHelper diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/UnwedgingTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/UnwedgingTest.kt index 8346430530..de4a928dc3 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/UnwedgingTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/UnwedgingTest.kt @@ -34,6 +34,7 @@ import org.matrix.android.sdk.api.session.crypto.MXCryptoError import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.content.EncryptedEventContent import org.matrix.android.sdk.api.session.events.model.toModel +import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.room.timeline.Timeline import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings @@ -97,7 +98,7 @@ class UnwedgingTest : InstrumentedTest { val roomFromBobPOV = bobSession.getRoom(aliceRoomId)!! val roomFromAlicePOV = aliceSession.getRoom(aliceRoomId)!! - val bobTimeline = roomFromBobPOV.createTimeline(null, TimelineSettings(20)) + val bobTimeline = roomFromBobPOV.timelineService().createTimeline(null, TimelineSettings(20)) bobTimeline.start() val bobFinalLatch = CountDownLatch(1) @@ -128,7 +129,7 @@ class UnwedgingTest : InstrumentedTest { messagesReceivedByBob = emptyList() // - Alice sends a 1st message with a 1st megolm session - roomFromAlicePOV.sendTextMessage("First message") + roomFromAlicePOV.sendService().sendTextMessage("First message") // Wait for the message to be received by Bob testHelper.await(latch) @@ -156,7 +157,7 @@ class UnwedgingTest : InstrumentedTest { Timber.i("## CRYPTO | testUnwedging: Alice sends a 2nd message with a 2nd megolm session") // - Alice sends a 2nd message with a 2nd megolm session - roomFromAlicePOV.sendTextMessage("Second message") + roomFromAlicePOV.sendService().sendTextMessage("Second message") // Wait for the message to be received by Bob testHelper.await(latch) @@ -185,7 +186,7 @@ class UnwedgingTest : InstrumentedTest { Timber.i("## CRYPTO | testUnwedging: Alice sends a 3rd message with a 3rd megolm session but a wedged olm session") // - Alice sends a 3rd message with a 3rd megolm session but a wedged olm session - roomFromAlicePOV.sendTextMessage("Third message") + roomFromAlicePOV.sendService().sendTextMessage("Third message") // Bob should not be able to decrypt, because the session key could not be sent } bobTimeline.removeListener(bobEventsListener) diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/encryption/EncryptionTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/encryption/EncryptionTest.kt index 84c9487e03..85b6c21df3 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/encryption/EncryptionTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/encryption/EncryptionTest.kt @@ -28,6 +28,7 @@ import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.content.EncryptionEventContent import org.matrix.android.sdk.api.session.events.model.toContent +import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.room.Room import org.matrix.android.sdk.api.session.room.send.SendState import org.matrix.android.sdk.api.session.room.timeline.Timeline @@ -48,7 +49,7 @@ class EncryptionTest : InstrumentedTest { fun test_EncryptionEvent() { performTest(roomShouldBeEncrypted = false) { room -> // Send an encryption Event as an Event (and not as a state event) - room.sendEvent( + room.sendService().sendEvent( eventType = EventType.STATE_ROOM_ENCRYPTION, content = EncryptionEventContent(algorithm = MXCRYPTO_ALGORITHM_MEGOLM).toContent() ) @@ -60,7 +61,7 @@ class EncryptionTest : InstrumentedTest { performTest(roomShouldBeEncrypted = true) { room -> runBlocking { // Send an encryption Event as a State Event - room.sendStateEvent( + room.stateService().sendStateEvent( eventType = EventType.STATE_ROOM_ENCRYPTION, stateKey = "", body = EncryptionEventContent(algorithm = MXCRYPTO_ALGORITHM_MEGOLM).toContent() @@ -75,9 +76,9 @@ class EncryptionTest : InstrumentedTest { val aliceSession = cryptoTestData.firstSession val room = aliceSession.getRoom(cryptoTestData.roomId)!! - room.isEncrypted() shouldBe false + room.roomCryptoService().isEncrypted() shouldBe false - val timeline = room.createTimeline(null, TimelineSettings(10)) + val timeline = room.timelineService().createTimeline(null, TimelineSettings(10)) val latch = CountDownLatch(1) val timelineListener = object : Timeline.Listener { override fun onTimelineFailure(throwable: Throwable) { @@ -105,7 +106,7 @@ class EncryptionTest : InstrumentedTest { testHelper.await(latch) timeline.dispose() testHelper.waitWithLatch { - room.isEncrypted() shouldBe roomShouldBeEncrypted + room.roomCryptoService().isEncrypted() shouldBe roomShouldBeEncrypted it.countDown() } cryptoTestData.cleanUp(testHelper) diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/gossiping/KeyShareTests.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/gossiping/KeyShareTests.kt index 5e271c6910..592d24fb69 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/gossiping/KeyShareTests.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/gossiping/KeyShareTests.kt @@ -50,6 +50,8 @@ import org.matrix.android.sdk.api.session.crypto.verification.VerificationTransa import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxState import org.matrix.android.sdk.api.session.events.model.content.EncryptedEventContent import org.matrix.android.sdk.api.session.events.model.toModel +import org.matrix.android.sdk.api.session.getRoom +import org.matrix.android.sdk.api.session.room.getTimelineEvent import org.matrix.android.sdk.api.session.room.model.RoomDirectoryVisibility import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams import org.matrix.android.sdk.api.session.room.model.message.MessageContent @@ -73,7 +75,7 @@ class KeyShareTests : InstrumentedTest { // Create an encrypted room and add a message val roomId = commonTestHelper.runBlockingTest { - aliceSession.createRoom( + aliceSession.roomService().createRoom( CreateRoomParams().apply { visibility = RoomDirectoryVisibility.PRIVATE enableEncryption() @@ -83,7 +85,7 @@ class KeyShareTests : InstrumentedTest { val room = aliceSession.getRoom(roomId) assertNotNull(room) Thread.sleep(4_000) - assertTrue(room?.isEncrypted() == true) + assertTrue(room?.roomCryptoService()?.isEncrypted() == true) val sentEventId = commonTestHelper.sendTextMessage(room!!, "My Message", 1).first().eventId // Open a new sessionx @@ -340,7 +342,7 @@ class KeyShareTests : InstrumentedTest { // Create an encrypted room and send a couple of messages val roomId = commonTestHelper.runBlockingTest { - aliceSession.createRoom( + aliceSession.roomService().createRoom( CreateRoomParams().apply { visibility = RoomDirectoryVisibility.PRIVATE enableEncryption() @@ -350,7 +352,7 @@ class KeyShareTests : InstrumentedTest { val roomAlicePov = aliceSession.getRoom(roomId) assertNotNull(roomAlicePov) Thread.sleep(1_000) - assertTrue(roomAlicePov?.isEncrypted() == true) + assertTrue(roomAlicePov?.roomCryptoService()?.isEncrypted() == true) val secondEventId = commonTestHelper.sendTextMessage(roomAlicePov!!, "Message", 3)[1].eventId // Create bob session @@ -374,11 +376,11 @@ class KeyShareTests : InstrumentedTest { // Let alice invite bob commonTestHelper.runBlockingTest { - roomAlicePov.invite(bobSession.myUserId, null) + roomAlicePov.membershipService().invite(bobSession.myUserId, null) } commonTestHelper.runBlockingTest { - bobSession.joinRoom(roomAlicePov.roomId, null, emptyList()) + bobSession.roomService().joinRoom(roomAlicePov.roomId, null, emptyList()) } // we want to discard alice outbound session diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/gossiping/WithHeldTests.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/gossiping/WithHeldTests.kt index 55bb03278c..bad9fd0f68 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/gossiping/WithHeldTests.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/gossiping/WithHeldTests.kt @@ -33,6 +33,8 @@ import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.content.EncryptedEventContent import org.matrix.android.sdk.api.session.events.model.content.WithHeldCode import org.matrix.android.sdk.api.session.events.model.toModel +import org.matrix.android.sdk.api.session.getRoom +import org.matrix.android.sdk.api.session.room.getTimelineEvent import org.matrix.android.sdk.common.CommonTestHelper import org.matrix.android.sdk.common.CryptoTestHelper import org.matrix.android.sdk.common.MockOkHttpInterceptor diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupTest.kt index 063c0c0ca3..3220f161fa 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupTest.kt @@ -41,6 +41,7 @@ import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysVersion import org.matrix.android.sdk.api.session.crypto.keysbackup.MegolmBackupCreationInfo import org.matrix.android.sdk.api.session.crypto.keysbackup.toKeysVersionResult import org.matrix.android.sdk.api.session.crypto.model.ImportRoomKeysResult +import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.common.CommonTestHelper import org.matrix.android.sdk.common.CryptoTestHelper import org.matrix.android.sdk.common.TestConstants diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/ssss/QuadSTests.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/ssss/QuadSTests.kt index d6baa4b1e0..a882f69013 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/ssss/QuadSTests.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/ssss/QuadSTests.kt @@ -60,7 +60,7 @@ class QuadSTests : InstrumentedTest { val aliceSession = testHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true)) - val quadS = aliceSession.sharedSecretStorageService + val quadS = aliceSession.sharedSecretStorageService() val TEST_KEY_ID = "my.test.Key" @@ -120,7 +120,7 @@ class QuadSTests : InstrumentedTest { // Store a secret val clearSecret = "42".toByteArray().toBase64NoPadding() testHelper.runBlockingTest { - aliceSession.sharedSecretStorageService.storeSecret( + aliceSession.sharedSecretStorageService().storeSecret( "secret.of.life", clearSecret, listOf(SharedSecretStorageService.KeyRef(null, keySpec)) // default key @@ -141,7 +141,7 @@ class QuadSTests : InstrumentedTest { // Try to decrypt?? val decryptedSecret = testHelper.runBlockingTest { - aliceSession.sharedSecretStorageService.getSecret( + aliceSession.sharedSecretStorageService().getSecret( "secret.of.life", null, // default key keySpec!! @@ -158,7 +158,7 @@ class QuadSTests : InstrumentedTest { val aliceSession = testHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true)) - val quadS = aliceSession.sharedSecretStorageService + val quadS = aliceSession.sharedSecretStorageService() val TEST_KEY_ID = "my.test.Key" @@ -187,7 +187,7 @@ class QuadSTests : InstrumentedTest { val mySecretText = "Lorem ipsum dolor sit amet, consectetur adipiscing elit" testHelper.runBlockingTest { - aliceSession.sharedSecretStorageService.storeSecret( + aliceSession.sharedSecretStorageService().storeSecret( "my.secret", mySecretText.toByteArray().toBase64NoPadding(), listOf( @@ -207,14 +207,14 @@ class QuadSTests : InstrumentedTest { // Assert that can decrypt with both keys testHelper.runBlockingTest { - aliceSession.sharedSecretStorageService.getSecret("my.secret", + aliceSession.sharedSecretStorageService().getSecret("my.secret", keyId1, RawBytesKeySpec.fromRecoveryKey(key1Info.recoveryKey)!! ) } testHelper.runBlockingTest { - aliceSession.sharedSecretStorageService.getSecret("my.secret", + aliceSession.sharedSecretStorageService().getSecret("my.secret", keyId2, RawBytesKeySpec.fromRecoveryKey(key2Info.recoveryKey)!! ) @@ -236,7 +236,7 @@ class QuadSTests : InstrumentedTest { val mySecretText = "Lorem ipsum dolor sit amet, consectetur adipiscing elit" testHelper.runBlockingTest { - aliceSession.sharedSecretStorageService.storeSecret( + aliceSession.sharedSecretStorageService().storeSecret( "my.secret", mySecretText.toByteArray().toBase64NoPadding(), listOf(SharedSecretStorageService.KeyRef(keyId1, RawBytesKeySpec.fromRecoveryKey(key1Info.recoveryKey))) @@ -245,7 +245,7 @@ class QuadSTests : InstrumentedTest { testHelper.runBlockingTest { try { - aliceSession.sharedSecretStorageService.getSecret("my.secret", + aliceSession.sharedSecretStorageService().getSecret("my.secret", keyId1, RawBytesKeySpec.fromPassphrase( "A bad passphrase", @@ -260,7 +260,7 @@ class QuadSTests : InstrumentedTest { // Now try with correct key testHelper.runBlockingTest { - aliceSession.sharedSecretStorageService.getSecret("my.secret", + aliceSession.sharedSecretStorageService().getSecret("my.secret", keyId1, RawBytesKeySpec.fromPassphrase( passphrase, @@ -292,7 +292,7 @@ class QuadSTests : InstrumentedTest { } private fun generatedSecret(session: Session, keyId: String, asDefault: Boolean = true): SsssKeyCreationInfo { - val quadS = session.sharedSecretStorageService + val quadS = session.sharedSecretStorageService() val testHelper = CommonTestHelper(context()) val creationInfo = testHelper.runBlockingTest { @@ -312,7 +312,7 @@ class QuadSTests : InstrumentedTest { } private fun generatedSecretFromPassphrase(session: Session, passphrase: String, keyId: String, asDefault: Boolean = true): SsssKeyCreationInfo { - val quadS = session.sharedSecretStorageService + val quadS = session.sharedSecretStorageService() val testHelper = CommonTestHelper(context()) val creationInfo = testHelper.runBlockingTest { diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/threads/ThreadMessagingTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/threads/ThreadMessagingTest.kt index dcb181f0c1..f6e08a576e 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/threads/ThreadMessagingTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/threads/ThreadMessagingTest.kt @@ -31,6 +31,7 @@ import org.matrix.android.sdk.InstrumentedTest import org.matrix.android.sdk.api.session.events.model.getRootThreadEventId import org.matrix.android.sdk.api.session.events.model.isTextMessage import org.matrix.android.sdk.api.session.events.model.isThread +import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.room.timeline.Timeline import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings import org.matrix.android.sdk.common.CommonTestHelper @@ -80,7 +81,7 @@ class ThreadMessagingTest : InstrumentedTest { replyInThread.root.getRootThreadEventId().shouldBeEqualTo(initMessage.root.eventId) // The init normal message should now be a root thread event - val timeline = aliceRoom.createTimeline(null, TimelineSettings(30)) + val timeline = aliceRoom.timelineService().createTimeline(null, TimelineSettings(30)) timeline.start() aliceSession.startSync(true) @@ -141,7 +142,7 @@ class ThreadMessagingTest : InstrumentedTest { replyInThread.root.getRootThreadEventId().shouldBeEqualTo(initMessage.root.eventId) // The init normal message should now be a root thread event - val timeline = aliceRoom.createTimeline(null, TimelineSettings(30)) + val timeline = aliceRoom.timelineService().createTimeline(null, TimelineSettings(30)) timeline.start() aliceSession.startSync(true) @@ -214,7 +215,7 @@ class ThreadMessagingTest : InstrumentedTest { } // The init normal message should now be a root thread event - val timeline = aliceRoom.createTimeline(null, TimelineSettings(30)) + val timeline = aliceRoom.timelineService().createTimeline(null, TimelineSettings(30)) timeline.start() aliceSession.startSync(true) @@ -309,7 +310,7 @@ class ThreadMessagingTest : InstrumentedTest { } // The init normal message should now be a root thread event - val timeline = aliceRoom.createTimeline(null, TimelineSettings(30)) + val timeline = aliceRoom.timelineService().createTimeline(null, TimelineSettings(30)) timeline.start() aliceSession.startSync(true) diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/PollAggregationTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/PollAggregationTest.kt index 6792d6ddfd..61ab6d4b40 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/PollAggregationTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/PollAggregationTest.kt @@ -30,6 +30,7 @@ import org.junit.runners.MethodSorters import org.matrix.android.sdk.InstrumentedTest import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.toModel +import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.room.model.PollResponseAggregatedSummary import org.matrix.android.sdk.api.session.room.model.PollSummaryContent import org.matrix.android.sdk.api.session.room.model.message.MessagePollContent @@ -57,10 +58,10 @@ class PollAggregationTest : InstrumentedTest { val roomFromBobPOV = cryptoTestData.secondSession!!.getRoom(cryptoTestData.roomId)!! // Bob creates a poll - roomFromBobPOV.sendPoll(PollType.DISCLOSED, pollQuestion, pollOptions) + roomFromBobPOV.sendService().sendPoll(PollType.DISCLOSED, pollQuestion, pollOptions) aliceSession.startSync(true) - val aliceTimeline = roomFromAlicePOV.createTimeline(null, TimelineSettings(30)) + val aliceTimeline = roomFromAlicePOV.timelineService().createTimeline(null, TimelineSettings(30)) aliceTimeline.start() val TOTAL_TEST_COUNT = 7 @@ -83,37 +84,37 @@ class PollAggregationTest : InstrumentedTest { // Poll has just been created. testInitialPollConditions(pollContent, pollSummary) lock.countDown() - roomFromBobPOV.voteToPoll(pollEventId, pollContent.getBestPollCreationInfo()?.answers?.firstOrNull()?.id ?: "") + roomFromBobPOV.sendService().voteToPoll(pollEventId, pollContent.getBestPollCreationInfo()?.answers?.firstOrNull()?.id ?: "") } TOTAL_TEST_COUNT - 1 -> { // Bob: Option 1 testBobVotesOption1(pollContent, pollSummary) lock.countDown() - roomFromBobPOV.voteToPoll(pollEventId, pollContent.getBestPollCreationInfo()?.answers?.get(1)?.id ?: "") + roomFromBobPOV.sendService().voteToPoll(pollEventId, pollContent.getBestPollCreationInfo()?.answers?.get(1)?.id ?: "") } TOTAL_TEST_COUNT - 2 -> { // Bob: Option 2 testBobChangesVoteToOption2(pollContent, pollSummary) lock.countDown() - roomFromAlicePOV.voteToPoll(pollEventId, pollContent.getBestPollCreationInfo()?.answers?.get(1)?.id ?: "") + roomFromAlicePOV.sendService().voteToPoll(pollEventId, pollContent.getBestPollCreationInfo()?.answers?.get(1)?.id ?: "") } TOTAL_TEST_COUNT - 3 -> { // Alice: Option 2, Bob: Option 2 testAliceAndBobVoteToOption2(pollContent, pollSummary) lock.countDown() - roomFromAlicePOV.voteToPoll(pollEventId, pollContent.getBestPollCreationInfo()?.answers?.firstOrNull()?.id ?: "") + roomFromAlicePOV.sendService().voteToPoll(pollEventId, pollContent.getBestPollCreationInfo()?.answers?.firstOrNull()?.id ?: "") } TOTAL_TEST_COUNT - 4 -> { // Alice: Option 1, Bob: Option 2 testAliceVotesOption1AndBobVotesOption2(pollContent, pollSummary) lock.countDown() - roomFromBobPOV.endPoll(pollEventId) + roomFromBobPOV.sendService().endPoll(pollEventId) } TOTAL_TEST_COUNT - 5 -> { // Alice: Option 1, Bob: Option 2 [poll is ended] testEndedPoll(pollSummary) lock.countDown() - roomFromAlicePOV.voteToPoll(pollEventId, pollContent.getBestPollCreationInfo()?.answers?.get(1)?.id ?: "") + roomFromAlicePOV.sendService().voteToPoll(pollEventId, pollContent.getBestPollCreationInfo()?.answers?.get(1)?.id ?: "") } TOTAL_TEST_COUNT - 6 -> { // Alice: Option 1 (ignore change), Bob: Option 2 [poll is ended] diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelineForwardPaginationTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelineForwardPaginationTest.kt index ee44af58b3..3864ea1cd1 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelineForwardPaginationTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelineForwardPaginationTest.kt @@ -30,6 +30,7 @@ import org.matrix.android.sdk.InstrumentedTest import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.toModel +import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.room.model.message.MessageContent import org.matrix.android.sdk.api.session.room.timeline.Timeline import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings @@ -74,7 +75,7 @@ class TimelineForwardPaginationTest : InstrumentedTest { // Alice clear the cache and restart the sync commonTestHelper.clearCacheAndSync(aliceSession) - val aliceTimeline = roomFromAlicePOV.createTimeline(null, TimelineSettings(30)) + val aliceTimeline = roomFromAlicePOV.timelineService().createTimeline(null, TimelineSettings(30)) aliceTimeline.start() // Alice sees the 10 last message of the room, and can only navigate BACKWARD diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelinePreviousLastForwardTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelinePreviousLastForwardTest.kt index c6d40bcaa2..5d09b74e6c 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelinePreviousLastForwardTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelinePreviousLastForwardTest.kt @@ -28,6 +28,7 @@ import org.matrix.android.sdk.InstrumentedTest import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.toModel +import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.room.model.message.MessageContent import org.matrix.android.sdk.api.session.room.timeline.Timeline import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings @@ -62,7 +63,7 @@ class TimelinePreviousLastForwardTest : InstrumentedTest { val roomFromAlicePOV = aliceSession.getRoom(aliceRoomId)!! val roomFromBobPOV = bobSession.getRoom(aliceRoomId)!! - val bobTimeline = roomFromBobPOV.createTimeline(null, TimelineSettings(30)) + val bobTimeline = roomFromBobPOV.timelineService().createTimeline(null, TimelineSettings(30)) bobTimeline.start() run { diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelineSimpleBackPaginationTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelineSimpleBackPaginationTest.kt index 53f76f1c46..251b2c614c 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelineSimpleBackPaginationTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelineSimpleBackPaginationTest.kt @@ -28,6 +28,7 @@ import org.matrix.android.sdk.InstrumentedTest import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.session.events.model.isTextMessage import org.matrix.android.sdk.api.session.events.model.toModel +import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.room.model.message.MessageTextContent import org.matrix.android.sdk.api.session.room.timeline.Timeline import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings @@ -65,7 +66,7 @@ class TimelineSimpleBackPaginationTest : InstrumentedTest { message, numberOfMessagesToSent) - val bobTimeline = roomFromBobPOV.createTimeline(null, TimelineSettings(30)) + val bobTimeline = roomFromBobPOV.timelineService().createTimeline(null, TimelineSettings(30)) bobTimeline.start() commonTestHelper.waitWithLatch(timeout = TestConstants.timeOutMillis * 10) { diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelineWithManyMembersTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelineWithManyMembersTest.kt index ce02b2b527..02430dda74 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelineWithManyMembersTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelineWithManyMembersTest.kt @@ -27,6 +27,7 @@ import org.junit.runners.MethodSorters import org.matrix.android.sdk.InstrumentedTest import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.session.events.model.toModel +import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.room.model.message.MessageContent import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings import org.matrix.android.sdk.common.CommonTestHelper @@ -71,7 +72,7 @@ class TimelineWithManyMembersTest : InstrumentedTest { for (index in 1 until cryptoTestData.sessions.size) { val session = cryptoTestData.sessions[index] val roomForCurrentMember = session.getRoom(cryptoTestData.roomId)!! - val timelineForCurrentMember = roomForCurrentMember.createTimeline(null, TimelineSettings(30)) + val timelineForCurrentMember = roomForCurrentMember.timelineService().createTimeline(null, TimelineSettings(30)) timelineForCurrentMember.start() session.startSync(true) diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/search/SearchMessagesTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/search/SearchMessagesTest.kt index fa07cf5a02..ab0bbe7f73 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/search/SearchMessagesTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/search/SearchMessagesTest.kt @@ -24,6 +24,7 @@ import org.junit.runners.JUnit4 import org.junit.runners.MethodSorters import org.matrix.android.sdk.InstrumentedTest import org.matrix.android.sdk.api.extensions.orFalse +import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.search.SearchResult import org.matrix.android.sdk.common.CommonTestHelper import org.matrix.android.sdk.common.CryptoTestData @@ -59,9 +60,10 @@ class SearchMessagesTest : InstrumentedTest { fun sendTextMessageAndSearchPartOfItUsingRoom() { doTest { cryptoTestData -> cryptoTestData.firstSession - .getRoom(cryptoTestData.roomId)!! + .searchService() .search( searchTerm = "lore", + roomId = cryptoTestData.roomId, limit = 10, includeProfile = true, afterLimit = 0, diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/space/SpaceCreationTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/space/SpaceCreationTest.kt index 3b0f7586cc..b9760c1bfc 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/space/SpaceCreationTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/space/SpaceCreationTest.kt @@ -29,6 +29,7 @@ import org.junit.runners.MethodSorters import org.matrix.android.sdk.InstrumentedTest import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.toModel +import org.matrix.android.sdk.api.session.room.getStateEvent import org.matrix.android.sdk.api.session.room.model.GuestAccess import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent import org.matrix.android.sdk.api.session.room.model.RoomGuestAccessContent @@ -147,7 +148,7 @@ class SpaceCreationTest : InstrumentedTest { // create a room var firstChild: String? = null commonTestHelper.waitWithLatch { - firstChild = aliceSession.createRoom(CreateRoomParams().apply { + firstChild = aliceSession.roomService().createRoom(CreateRoomParams().apply { this.name = "FirstRoom" this.topic = "Description of first room" this.preset = CreateRoomPreset.PRESET_PUBLIC_CHAT @@ -162,7 +163,7 @@ class SpaceCreationTest : InstrumentedTest { var secondChild: String? = null commonTestHelper.waitWithLatch { - secondChild = aliceSession.createRoom(CreateRoomParams().apply { + secondChild = aliceSession.roomService().createRoom(CreateRoomParams().apply { this.name = "SecondRoom" this.topic = "Description of second room" this.preset = CreateRoomPreset.PRESET_PUBLIC_CHAT diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/space/SpaceHierarchyTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/space/SpaceHierarchyTest.kt index 20faa81bb6..d2c8b52fc7 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/space/SpaceHierarchyTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/space/SpaceHierarchyTest.kt @@ -35,6 +35,9 @@ import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.toContent import org.matrix.android.sdk.api.session.events.model.toModel +import org.matrix.android.sdk.api.session.getRoom +import org.matrix.android.sdk.api.session.getRoomSummary +import org.matrix.android.sdk.api.session.room.getStateEvent import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesAllowEntry import org.matrix.android.sdk.api.session.room.model.RoomSummary @@ -68,7 +71,7 @@ class SpaceHierarchyTest : InstrumentedTest { var roomId = "" commonTestHelper.waitWithLatch { - roomId = session.createRoom(CreateRoomParams().apply { name = "General" }) + roomId = session.roomService().createRoom(CreateRoomParams().apply { name = "General" }) it.countDown() } @@ -203,27 +206,27 @@ class SpaceHierarchyTest : InstrumentedTest { var orphan1 = "" commonTestHelper.waitWithLatch { - orphan1 = session.createRoom(CreateRoomParams().apply { name = "O1" }) + orphan1 = session.roomService().createRoom(CreateRoomParams().apply { name = "O1" }) it.countDown() } var orphan2 = "" commonTestHelper.waitWithLatch { - orphan2 = session.createRoom(CreateRoomParams().apply { name = "O2" }) + orphan2 = session.roomService().createRoom(CreateRoomParams().apply { name = "O2" }) it.countDown() } - val allRooms = session.getRoomSummaries(roomSummaryQueryParams { excludeType = listOf(RoomType.SPACE) }) + val allRooms = session.roomService().getRoomSummaries(roomSummaryQueryParams { excludeType = listOf(RoomType.SPACE) }) assertEquals("Unexpected number of rooms", 9, allRooms.size) - val orphans = session.getFlattenRoomSummaryChildrenOf(null) + val orphans = session.roomService().getFlattenRoomSummaryChildrenOf(null) assertEquals("Unexpected number of orphan rooms", 2, orphans.size) assertTrue("O1 should be an orphan", orphans.any { it.roomId == orphan1 }) assertTrue("O2 should be an orphan ${orphans.map { it.name }}", orphans.any { it.roomId == orphan2 }) - val aChildren = session.getFlattenRoomSummaryChildrenOf(spaceAInfo.spaceId) + val aChildren = session.roomService().getFlattenRoomSummaryChildrenOf(spaceAInfo.spaceId) assertEquals("Unexpected number of flatten child rooms", 4, aChildren.size) assertTrue("A1 should be a child of A", aChildren.any { it.name == "A1" }) @@ -233,13 +236,13 @@ class SpaceHierarchyTest : InstrumentedTest { // Add a non canonical child and check that it does not appear as orphan commonTestHelper.waitWithLatch { - val a3 = session.createRoom(CreateRoomParams().apply { name = "A3" }) + val a3 = session.roomService().createRoom(CreateRoomParams().apply { name = "A3" }) spaceA!!.addChildren(a3, viaServers, null, false) it.countDown() } Thread.sleep(6_000) - val orphansUpdate = session.getRoomSummaries(roomSummaryQueryParams { + val orphansUpdate = session.roomService().getRoomSummaries(roomSummaryQueryParams { activeSpaceFilter = ActiveSpaceFilter.ActiveSpace(null) }) assertEquals("Unexpected number of orphan rooms ${orphansUpdate.map { it.name }}", 2, orphansUpdate.size) @@ -279,7 +282,7 @@ class SpaceHierarchyTest : InstrumentedTest { // A -> C -> A - val aChildren = session.getFlattenRoomSummaryChildrenOf(spaceAInfo.spaceId) + val aChildren = session.roomService().getFlattenRoomSummaryChildrenOf(spaceAInfo.spaceId) assertEquals("Unexpected number of flatten child rooms ${aChildren.map { it.name }}", 4, aChildren.size) assertTrue("A1 should be a child of A", aChildren.any { it.name == "A1" }) @@ -319,7 +322,7 @@ class SpaceHierarchyTest : InstrumentedTest { commonTestHelper.waitWithLatch { latch -> - val flatAChildren = session.getFlattenRoomSummaryChildrenOfLive(spaceAInfo.spaceId) + val flatAChildren = session.roomService().getFlattenRoomSummaryChildrenOfLive(spaceAInfo.spaceId) val childObserver = object : Observer> { override fun onChanged(children: List?) { // Log.d("## TEST", "Space A flat children update : ${children?.map { it.name }}") @@ -346,7 +349,7 @@ class SpaceHierarchyTest : InstrumentedTest { val bRoomId = spaceBInfo.roomIds.first() commonTestHelper.waitWithLatch { latch -> - val flatAChildren = session.getFlattenRoomSummaryChildrenOfLive(spaceAInfo.spaceId) + val flatAChildren = session.roomService().getFlattenRoomSummaryChildrenOfLive(spaceAInfo.spaceId) val childObserver = object : Observer> { override fun onChanged(children: List?) { System.out.println("## TEST | Space A flat children update : ${children?.map { it.name }}") @@ -359,7 +362,7 @@ class SpaceHierarchyTest : InstrumentedTest { } // part from b room - session.leaveRoom(bRoomId) + session.roomService().leaveRoom(bRoomId) // The room should have disapear from flat children flatAChildren.observeForever(childObserver) } @@ -385,7 +388,7 @@ class SpaceHierarchyTest : InstrumentedTest { val viaServers = listOf(session.sessionParams.homeServerHost ?: "") roomIds = childInfo.map { entry -> - session.createRoom(CreateRoomParams().apply { name = entry.first }) + session.roomService().createRoom(CreateRoomParams().apply { name = entry.first }) } roomIds.forEachIndexed { index, roomId -> syncedSpace!!.addChildren(roomId, viaServers, null, childInfo[index].second) @@ -414,8 +417,9 @@ class SpaceHierarchyTest : InstrumentedTest { roomIds = childInfo.map { entry -> val homeServerCapabilities = session + .homeServerCapabilitiesService() .getHomeServerCapabilities() - session.createRoom(CreateRoomParams().apply { + session.roomService().createRoom(CreateRoomParams().apply { name = entry.first this.featurePreset = RestrictedRoomPreset( homeServerCapabilities, @@ -475,7 +479,9 @@ class SpaceHierarchyTest : InstrumentedTest { // + C // + c1, c2 - val rootSpaces = session.spaceService().getRootSpaceSummaries() + val rootSpaces = commonTestHelper.runBlockingTest { + session.spaceService().getRootSpaceSummaries() + } assertEquals("Unexpected number of root spaces ${rootSpaces.map { it.name }}", 2, rootSpaces.size) @@ -494,22 +500,22 @@ class SpaceHierarchyTest : InstrumentedTest { )) commonTestHelper.runBlockingTest { - aliceSession.getRoom(spaceAInfo.spaceId)!!.invite(bobSession.myUserId, null) + aliceSession.getRoom(spaceAInfo.spaceId)!!.membershipService().invite(bobSession.myUserId, null) } commonTestHelper.runBlockingTest { - bobSession.joinRoom(spaceAInfo.spaceId, null, emptyList()) + bobSession.roomService().joinRoom(spaceAInfo.spaceId, null, emptyList()) } var bobRoomId = "" commonTestHelper.waitWithLatch { - bobRoomId = bobSession.createRoom(CreateRoomParams().apply { name = "A Bob Room" }) - bobSession.getRoom(bobRoomId)!!.invite(aliceSession.myUserId) + bobRoomId = bobSession.roomService().createRoom(CreateRoomParams().apply { name = "A Bob Room" }) + bobSession.getRoom(bobRoomId)!!.membershipService().invite(aliceSession.myUserId) it.countDown() } commonTestHelper.runBlockingTest { - aliceSession.joinRoom(bobRoomId) + aliceSession.roomService().joinRoom(bobRoomId) } commonTestHelper.waitWithLatch { latch -> @@ -549,7 +555,7 @@ class SpaceHierarchyTest : InstrumentedTest { ?.setUserPowerLevel(aliceSession.myUserId, Role.Admin.value) ?.toContent() - room.sendStateEvent(EventType.STATE_ROOM_POWER_LEVELS, stateKey = "", newPowerLevelsContent!!) + room.stateService().sendStateEvent(EventType.STATE_ROOM_POWER_LEVELS, stateKey = "", newPowerLevelsContent!!) it.countDown() } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/Matrix.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/Matrix.kt index e7b4b766ad..217f7e3da8 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/Matrix.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/Matrix.kt @@ -43,7 +43,8 @@ import javax.inject.Inject /** * This is the main entry point to the matrix sdk. - * To get the singleton instance, use getInstance static method. + *
+ * See [Companion.createInstance] to create an instance. The app should create and manage the instance itself. */ class Matrix private constructor(context: Context, matrixConfiguration: MatrixConfiguration) { @@ -74,9 +75,7 @@ class Matrix private constructor(context: Context, matrixConfiguration: MatrixCo fun getUserAgent() = userAgentHolder.userAgent - fun authenticationService(): AuthenticationService { - return authenticationService - } + fun authenticationService() = authenticationService fun rawService() = rawService @@ -84,9 +83,7 @@ class Matrix private constructor(context: Context, matrixConfiguration: MatrixCo fun homeServerHistoryService() = homeServerHistoryService - fun legacySessionImporter(): LegacySessionImporter { - return legacySessionImporter - } + fun legacySessionImporter() = legacySessionImporter fun workerFactory(): WorkerFactory = matrixWorkerFactory @@ -143,6 +140,9 @@ class Matrix private constructor(context: Context, matrixConfiguration: MatrixCo return instance } + /** + * @return a String with details about the Matrix SDK version + */ fun getSdkVersion(): String { return BuildConfig.SDK_VERSION + " (" + BuildConfig.GIT_SDK_REVISION + ")" } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt index 2ad0ae9e0d..19502f0b46 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt @@ -24,10 +24,8 @@ import org.matrix.android.sdk.api.MatrixCoroutineDispatchers import org.matrix.android.sdk.api.auth.data.SessionParams import org.matrix.android.sdk.api.failure.GlobalError import org.matrix.android.sdk.api.federation.FederationService -import org.matrix.android.sdk.api.pushrules.PushRuleService import org.matrix.android.sdk.api.session.account.AccountService import org.matrix.android.sdk.api.session.accountdata.SessionAccountDataService -import org.matrix.android.sdk.api.session.cache.CacheService import org.matrix.android.sdk.api.session.call.CallSignalingService import org.matrix.android.sdk.api.session.content.ContentUploadStateTracker import org.matrix.android.sdk.api.session.content.ContentUrlResolver @@ -47,6 +45,7 @@ import org.matrix.android.sdk.api.session.permalinks.PermalinkService import org.matrix.android.sdk.api.session.presence.PresenceService import org.matrix.android.sdk.api.session.profile.ProfileService import org.matrix.android.sdk.api.session.pushers.PushersService +import org.matrix.android.sdk.api.session.pushrules.PushRuleService import org.matrix.android.sdk.api.session.room.RoomDirectoryService import org.matrix.android.sdk.api.session.room.RoomService import org.matrix.android.sdk.api.session.search.SearchService @@ -68,26 +67,7 @@ import org.matrix.android.sdk.api.session.widgets.WidgetService * This interface defines interactions with a session. * An instance of a session will be provided by the SDK. */ -interface Session : - RoomService, - RoomDirectoryService, - GroupService, - UserService, - CacheService, - SignOutService, - FilterService, - TermsService, - EventService, - ProfileService, - PresenceService, - PushRuleService, - PushersService, - SyncStatusService, - HomeServerCapabilitiesService, - SecureStorageService, - AccountService, - ToDeviceService, - EventStreamService { +interface Session { val coroutineDispatchers: MatrixCoroutineDispatchers @@ -144,6 +124,11 @@ interface Session : */ fun stopSync() + /** + * Clear cache of the session + */ + suspend fun clearCache() + /** * This method allows to listen the sync state. * @return a [LiveData] of [SyncState]. @@ -206,6 +191,96 @@ interface Session : */ fun identityService(): IdentityService + /** + * Returns the HomeServerCapabilities service associated with the session + */ + fun homeServerCapabilitiesService(): HomeServerCapabilitiesService + + /** + * Returns the RoomService associated with the session + */ + fun roomService(): RoomService + + /** + * Returns the RoomDirectoryService associated with the session + */ + fun roomDirectoryService(): RoomDirectoryService + + /** + * Returns the GroupService associated with the session + */ + fun groupService(): GroupService + + /** + * Returns the UserService associated with the session + */ + fun userService(): UserService + + /** + * Returns the SignOutService associated with the session + */ + fun signOutService(): SignOutService + + /** + * Returns the FilterService associated with the session + */ + fun filterService(): FilterService + + /** + * Returns the PushRuleService associated with the session + */ + fun pushRuleService(): PushRuleService + + /** + * Returns the PushersService associated with the session + */ + fun pushersService(): PushersService + + /** + * Returns the EventService associated with the session + */ + fun eventService(): EventService + + /** + * Returns the TermsService associated with the session + */ + fun termsService(): TermsService + + /** + * Returns the SyncStatusService associated with the session + */ + fun syncStatusService(): SyncStatusService + + /** + * Returns the SecureStorageService associated with the session + */ + fun secureStorageService(): SecureStorageService + + /** + * Returns the ProfileService associated with the session + */ + fun profileService(): ProfileService + + /** + * Returns the PresenceService associated with the session + */ + fun presenceService(): PresenceService + + /** + * Returns the AccountService associated with the session + */ + fun accountService(): AccountService + + /** + * Returns the ToDeviceService associated with the session + */ + fun toDeviceService(): ToDeviceService + + /** + * Returns the EventStreamService associated with the session + */ + fun eventStreamService(): EventStreamService + /** * Returns the widget service associated with the session */ @@ -266,6 +341,11 @@ interface Session : */ fun accountDataService(): SessionAccountDataService + /** + * Returns the SharedSecretStorageService associated with the session + */ + fun sharedSecretStorageService(): SharedSecretStorageService + /** * Add a listener to the session. * @param listener the listener to add. @@ -303,8 +383,6 @@ interface Session : fun onGlobalError(session: Session, globalError: GlobalError) = Unit } - val sharedSecretStorageService: SharedSecretStorageService - fun getUiaSsoFallbackUrl(authenticationSessionId: String): String /** diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/SessionExtensions.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/SessionExtensions.kt new file mode 100644 index 0000000000..aeb0e7e4ee --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/SessionExtensions.kt @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.api.session + +import org.matrix.android.sdk.api.session.room.Room +import org.matrix.android.sdk.api.session.room.model.RoomSummary +import org.matrix.android.sdk.api.session.user.model.User + +/** + * Get a room using the RoomService of a Session + */ +fun Session.getRoom(roomId: String): Room? = roomService().getRoom(roomId) + +/** + * Get a room summary using the RoomService of a Session + */ +fun Session.getRoomSummary(roomIdOrAlias: String): RoomSummary? = roomService().getRoomSummary(roomIdOrAlias) + +/** + * Get a user using the UserService of a Session + */ +fun Session.getUser(userId: String): User? = userService().getUser(userId) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/Action.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/Action.kt similarity index 97% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/Action.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/Action.kt index 30289531e7..7790942d84 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/Action.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/Action.kt @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.matrix.android.sdk.api.pushrules +package org.matrix.android.sdk.api.session.pushrules -import org.matrix.android.sdk.api.pushrules.rest.PushRule +import org.matrix.android.sdk.api.session.pushrules.rest.PushRule import timber.log.Timber sealed class Action { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/Condition.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/Condition.kt similarity index 93% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/Condition.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/Condition.kt index 04cccf7319..df5b056c2e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/Condition.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/Condition.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.matrix.android.sdk.api.pushrules +package org.matrix.android.sdk.api.session.pushrules import org.matrix.android.sdk.api.session.events.model.Event diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/ConditionResolver.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/ConditionResolver.kt similarity index 96% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/ConditionResolver.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/ConditionResolver.kt index 0a7366e5d2..f8a930f987 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/ConditionResolver.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/ConditionResolver.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.matrix.android.sdk.api.pushrules +package org.matrix.android.sdk.api.session.pushrules import org.matrix.android.sdk.api.session.events.model.Event diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/ContainsDisplayNameCondition.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/ContainsDisplayNameCondition.kt similarity index 97% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/ContainsDisplayNameCondition.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/ContainsDisplayNameCondition.kt index 7f43023873..69dd14ddc2 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/ContainsDisplayNameCondition.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/ContainsDisplayNameCondition.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.matrix.android.sdk.api.pushrules +package org.matrix.android.sdk.api.session.pushrules import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.EventType diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/EventMatchCondition.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/EventMatchCondition.kt similarity index 98% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/EventMatchCondition.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/EventMatchCondition.kt index 65a13b4fec..8875807b8a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/EventMatchCondition.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/EventMatchCondition.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.matrix.android.sdk.api.pushrules +package org.matrix.android.sdk.api.session.pushrules import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.internal.di.MoshiProvider diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/Kind.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/Kind.kt similarity index 96% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/Kind.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/Kind.kt index 293a06af9f..463f3c2a73 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/Kind.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/Kind.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.matrix.android.sdk.api.pushrules +package org.matrix.android.sdk.api.session.pushrules enum class Kind(val value: String) { EventMatch("event_match"), diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/PushEvents.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/PushEvents.kt similarity index 88% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/PushEvents.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/PushEvents.kt index 466e345cad..ee460d7076 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/PushEvents.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/PushEvents.kt @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.matrix.android.sdk.api.pushrules +package org.matrix.android.sdk.api.session.pushrules -import org.matrix.android.sdk.api.pushrules.rest.PushRule import org.matrix.android.sdk.api.session.events.model.Event +import org.matrix.android.sdk.api.session.pushrules.rest.PushRule data class PushEvents( val matchedEvents: List>, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/PushRuleService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/PushRuleService.kt similarity index 91% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/PushRuleService.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/PushRuleService.kt index 76885d8545..abbdbf8104 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/PushRuleService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/PushRuleService.kt @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.matrix.android.sdk.api.pushrules +package org.matrix.android.sdk.api.session.pushrules import androidx.lifecycle.LiveData -import org.matrix.android.sdk.api.pushrules.rest.PushRule -import org.matrix.android.sdk.api.pushrules.rest.RuleSet import org.matrix.android.sdk.api.session.events.model.Event +import org.matrix.android.sdk.api.session.pushrules.rest.PushRule +import org.matrix.android.sdk.api.session.pushrules.rest.RuleSet interface PushRuleService { /** diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/RoomMemberCountCondition.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/RoomMemberCountCondition.kt similarity index 94% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/RoomMemberCountCondition.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/RoomMemberCountCondition.kt index 328e6dae11..6973ff1372 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/RoomMemberCountCondition.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/RoomMemberCountCondition.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.matrix.android.sdk.api.pushrules +package org.matrix.android.sdk.api.session.pushrules import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.internal.session.room.RoomGetter @@ -44,7 +44,7 @@ class RoomMemberCountCondition( // Parse the is field into prefix and number the first time val (prefix, count) = parseIsField() ?: return false - val numMembers = room.getNumberOfJoinedMembers() + val numMembers = room.membershipService().getNumberOfJoinedMembers() return when (prefix) { "<" -> numMembers < count diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/RuleIds.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/RuleIds.kt similarity index 97% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/RuleIds.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/RuleIds.kt index 5b14e97d5e..4f35fb79c3 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/RuleIds.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/RuleIds.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.matrix.android.sdk.api.pushrules +package org.matrix.android.sdk.api.session.pushrules /** * Known rule ids diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/RuleScope.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/RuleScope.kt similarity index 92% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/RuleScope.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/RuleScope.kt index 7c1edc1aca..307b9db042 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/RuleScope.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/RuleScope.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.matrix.android.sdk.api.pushrules +package org.matrix.android.sdk.api.session.pushrules object RuleScope { const val GLOBAL = "global" diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/RuleSetKey.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/RuleSetKey.kt similarity index 95% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/RuleSetKey.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/RuleSetKey.kt index 5b6f6713f8..7b8f4c9f95 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/RuleSetKey.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/RuleSetKey.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.matrix.android.sdk.api.pushrules +package org.matrix.android.sdk.api.session.pushrules /** * Ref: https://matrix.org/docs/spec/client_server/latest#get-matrix-client-r0-pushrules diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/SenderNotificationPermissionCondition.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/SenderNotificationPermissionCondition.kt similarity index 97% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/SenderNotificationPermissionCondition.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/SenderNotificationPermissionCondition.kt index 6675fb0ff5..82f5023c2f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/SenderNotificationPermissionCondition.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/SenderNotificationPermissionCondition.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.matrix.android.sdk.api.pushrules +package org.matrix.android.sdk.api.session.pushrules import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/rest/PushCondition.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/rest/PushCondition.kt similarity index 84% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/rest/PushCondition.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/rest/PushCondition.kt index b31a1e6343..1fc8329535 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/rest/PushCondition.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/rest/PushCondition.kt @@ -13,17 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.matrix.android.sdk.api.pushrules.rest +package org.matrix.android.sdk.api.session.pushrules.rest import com.squareup.moshi.Json import com.squareup.moshi.JsonClass -import org.matrix.android.sdk.api.pushrules.Condition -import org.matrix.android.sdk.api.pushrules.ContainsDisplayNameCondition -import org.matrix.android.sdk.api.pushrules.EventMatchCondition -import org.matrix.android.sdk.api.pushrules.Kind -import org.matrix.android.sdk.api.pushrules.RoomMemberCountCondition -import org.matrix.android.sdk.api.pushrules.RuleIds -import org.matrix.android.sdk.api.pushrules.SenderNotificationPermissionCondition +import org.matrix.android.sdk.api.session.pushrules.Condition +import org.matrix.android.sdk.api.session.pushrules.ContainsDisplayNameCondition +import org.matrix.android.sdk.api.session.pushrules.EventMatchCondition +import org.matrix.android.sdk.api.session.pushrules.Kind +import org.matrix.android.sdk.api.session.pushrules.RoomMemberCountCondition +import org.matrix.android.sdk.api.session.pushrules.RuleIds +import org.matrix.android.sdk.api.session.pushrules.SenderNotificationPermissionCondition import timber.log.Timber /** diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/rest/PushRule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/rest/PushRule.kt similarity index 94% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/rest/PushRule.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/rest/PushRule.kt index 31d7770a9f..270ffb2940 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/rest/PushRule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/rest/PushRule.kt @@ -14,14 +14,14 @@ * limitations under the License. */ -package org.matrix.android.sdk.api.pushrules.rest +package org.matrix.android.sdk.api.session.pushrules.rest import com.squareup.moshi.Json import com.squareup.moshi.JsonClass import org.matrix.android.sdk.api.extensions.orFalse -import org.matrix.android.sdk.api.pushrules.Action -import org.matrix.android.sdk.api.pushrules.getActions -import org.matrix.android.sdk.api.pushrules.toJson +import org.matrix.android.sdk.api.session.pushrules.Action +import org.matrix.android.sdk.api.session.pushrules.getActions +import org.matrix.android.sdk.api.session.pushrules.toJson /** * Ref: https://matrix.org/docs/spec/client_server/latest#get-matrix-client-r0-pushrules diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/rest/RuleSet.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/rest/RuleSet.kt similarity index 93% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/rest/RuleSet.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/rest/RuleSet.kt index 46f5148714..5bf42b8252 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/rest/RuleSet.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/rest/RuleSet.kt @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.matrix.android.sdk.api.pushrules.rest +package org.matrix.android.sdk.api.session.pushrules.rest import com.squareup.moshi.Json import com.squareup.moshi.JsonClass -import org.matrix.android.sdk.api.pushrules.RuleIds -import org.matrix.android.sdk.api.pushrules.RuleSetKey +import org.matrix.android.sdk.api.session.pushrules.RuleIds +import org.matrix.android.sdk.api.session.pushrules.RuleSetKey /** * Ref: https://matrix.org/docs/spec/client_server/latest#get-matrix-client-r0-pushrules diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/Room.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/Room.kt index be65b883b3..1f990f4c0a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/Room.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/Room.kt @@ -38,33 +38,13 @@ import org.matrix.android.sdk.api.session.room.timeline.TimelineService import org.matrix.android.sdk.api.session.room.typing.TypingService import org.matrix.android.sdk.api.session.room.uploads.UploadsService import org.matrix.android.sdk.api.session.room.version.RoomVersionService -import org.matrix.android.sdk.api.session.search.SearchResult import org.matrix.android.sdk.api.session.space.Space import org.matrix.android.sdk.api.util.Optional /** * This interface defines methods to interact within a room. */ -interface Room : - TimelineService, - ThreadsService, - ThreadsLocalService, - SendService, - DraftService, - ReadService, - TypingService, - AliasService, - TagsService, - MembershipService, - StateService, - UploadsService, - ReportingService, - RoomCallService, - RelationService, - RoomCryptoService, - RoomPushRuleService, - RoomAccountDataService, - RoomVersionService { +interface Room { val coroutineDispatchers: MatrixCoroutineDispatchers @@ -84,28 +64,103 @@ interface Room : */ fun roomSummary(): RoomSummary? - /** - * Generic function to search a term in a room. - * Ref: https://matrix.org/docs/spec/client_server/latest#module-search - * @param searchTerm the term to search - * @param nextBatch the token that retrieved from the previous response. Should be provided to get the next batch of results - * @param orderByRecent if true, the most recent message events will return in the first places of the list - * @param limit the maximum number of events to return. - * @param beforeLimit how many events before the result are returned. - * @param afterLimit how many events after the result are returned. - * @param includeProfile requests that the server returns the historic profile information for the users that sent the events that were returned. - * @return The search result - */ - suspend fun search(searchTerm: String, - nextBatch: String?, - orderByRecent: Boolean, - limit: Int, - beforeLimit: Int, - afterLimit: Int, - includeProfile: Boolean): SearchResult - /** * Use this room as a Space, if the type is correct. */ fun asSpace(): Space? + + /** + * Get the TimelineService associated to this Room + */ + fun timelineService(): TimelineService + + /** + * Get the ThreadsService associated to this Room + */ + fun threadsService(): ThreadsService + + /** + * Get the ThreadsLocalService associated to this Room + */ + fun threadsLocalService(): ThreadsLocalService + + /** + * Get the SendService associated to this Room + */ + fun sendService(): SendService + + /** + * Get the DraftService associated to this Room + */ + fun draftService(): DraftService + + /** + * Get the ReadService associated to this Room + */ + fun readService(): ReadService + + /** + * Get the TypingService associated to this Room + */ + fun typingService(): TypingService + + /** + * Get the AliasService associated to this Room + */ + fun aliasService(): AliasService + + /** + * Get the TagsService associated to this Room + */ + fun tagsService(): TagsService + + /** + * Get the MembershipService associated to this Room + */ + fun membershipService(): MembershipService + + /** + * Get the StateService associated to this Room + */ + fun stateService(): StateService + + /** + * Get the UploadsService associated to this Room + */ + fun uploadsService(): UploadsService + + /** + * Get the ReportingService associated to this Room + */ + fun reportingService(): ReportingService + + /** + * Get the RoomCallService associated to this Room + */ + fun roomCallService(): RoomCallService + + /** + * Get the RelationService associated to this Room + */ + fun relationService(): RelationService + + /** + * Get the RoomCryptoService associated to this Room + */ + fun roomCryptoService(): RoomCryptoService + + /** + * Get the RoomPushRuleService associated to this Room + */ + fun roomPushRuleService(): RoomPushRuleService + + /** + * Get the RoomAccountDataService associated to this Room + */ + fun roomAccountDataService(): RoomAccountDataService + + /** + * Get the RoomVersionService associated to this Room + */ + fun roomVersionService(): RoomVersionService } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomExtensions.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomExtensions.kt new file mode 100644 index 0000000000..ece9cfbfac --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomExtensions.kt @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.api.session.room + +import org.matrix.android.sdk.api.query.QueryStringValue +import org.matrix.android.sdk.api.session.events.model.Event +import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent + +/** + * Get a TimelineEvent using the TimelineService of a Room + */ +fun Room.getTimelineEvent(eventId: String): TimelineEvent? = + timelineService().getTimelineEvent(eventId) + +/** + * Get a StateEvent using the StateService of a Room + */ +fun Room.getStateEvent(eventType: String, stateKey: QueryStringValue = QueryStringValue.NoCondition): Event? = + stateService().getStateEvent(eventType, stateKey) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/EventAnnotationsSummary.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/EventAnnotationsSummary.kt index 0238eb6c8d..0aded20339 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/EventAnnotationsSummary.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/EventAnnotationsSummary.kt @@ -15,10 +15,12 @@ */ package org.matrix.android.sdk.api.session.room.model +import org.matrix.android.sdk.api.session.room.model.livelocation.LiveLocationShareAggregatedSummary + data class EventAnnotationsSummary( - val eventId: String, val reactionsSummary: List = emptyList(), val editSummary: EditAggregatedSummary? = null, val pollResponseSummary: PollResponseAggregatedSummary? = null, - val referencesAggregatedSummary: ReferencesAggregatedSummary? = null + val referencesAggregatedSummary: ReferencesAggregatedSummary? = null, + val liveLocationShareAggregatedSummary: LiveLocationShareAggregatedSummary? = null, ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/ReferencesAggregatedSummary.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/ReferencesAggregatedSummary.kt index 31ac09efb8..49ba2d5ab6 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/ReferencesAggregatedSummary.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/ReferencesAggregatedSummary.kt @@ -22,7 +22,6 @@ import org.matrix.android.sdk.api.session.events.model.Content * of all events that are referencing the 'eventId' event via the RelationType.REFERENCE */ data class ReferencesAggregatedSummary( - val eventId: String, val content: Content?, val sourceEvents: List, val localEchos: List diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/livelocation/BeaconInfo.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/livelocation/LiveLocationShareAggregatedSummary.kt similarity index 53% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/livelocation/BeaconInfo.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/livelocation/LiveLocationShareAggregatedSummary.kt index 873edc0f1f..0b28d62f56 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/livelocation/BeaconInfo.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/livelocation/LiveLocationShareAggregatedSummary.kt @@ -1,5 +1,5 @@ /* - * Copyright 2022 The Matrix.org Foundation C.I.C. + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,18 +16,13 @@ package org.matrix.android.sdk.api.session.room.model.livelocation -import com.squareup.moshi.Json -import com.squareup.moshi.JsonClass +import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconLocationDataContent -@JsonClass(generateAdapter = true) -data class BeaconInfo( - @Json(name = "description") val description: String? = null, - /** - * Beacon should be considered as inactive after this timeout as milliseconds. - */ - @Json(name = "timeout") val timeout: Long? = null, - /** - * Should be set true to start sharing beacon. - */ - @Json(name = "live") val isLive: Boolean? = null +/** + * Aggregation info concerning a live location share. + */ +data class LiveLocationShareAggregatedSummary( + val isActive: Boolean?, + val endOfLiveTimestampMillis: Long?, + val lastLocationDataContent: MessageBeaconLocationDataContent?, ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/livelocation/LiveLocationBeaconContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageBeaconInfoContent.kt similarity index 57% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/livelocation/LiveLocationBeaconContent.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageBeaconInfoContent.kt index 106e76eafd..f75704a891 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/livelocation/LiveLocationBeaconContent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageBeaconInfoContent.kt @@ -14,60 +14,59 @@ * limitations under the License. */ -package org.matrix.android.sdk.api.session.room.model.livelocation +package org.matrix.android.sdk.api.session.room.model.message import com.squareup.moshi.Json import com.squareup.moshi.JsonClass import org.matrix.android.sdk.api.session.events.model.Content -import org.matrix.android.sdk.api.session.room.model.message.LocationAsset -import org.matrix.android.sdk.api.session.room.model.message.LocationAssetType -import org.matrix.android.sdk.api.session.room.model.message.MessageContent -import org.matrix.android.sdk.api.session.room.model.message.MessageLiveLocationContent -import org.matrix.android.sdk.api.session.room.model.message.MessageType import org.matrix.android.sdk.api.session.room.model.relation.RelationDefaultContent +/** + * Content of the state event of type + * [EventType.STATE_ROOM_BEACON_INFO][org.matrix.android.sdk.api.session.events.model.EventType.STATE_ROOM_BEACON_INFO] + * + * It contains general info related to a live location share. + * Locations are sent in a different message related to the state event. + * See [MessageBeaconLocationDataContent][org.matrix.android.sdk.api.session.room.model.message.MessageBeaconLocationDataContent] + */ @JsonClass(generateAdapter = true) -data class LiveLocationBeaconContent( +data class MessageBeaconInfoContent( /** * Local message type, not from server */ @Transient - override val msgType: String = MessageType.MSGTYPE_LIVE_LOCATION_STATE, + override val msgType: String = MessageType.MSGTYPE_BEACON_INFO, @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, /** - * Indicates user's intent to share ephemeral location. + * Optional description of the beacon. */ - @Json(name = "org.matrix.msc3672.beacon_info") val unstableBeaconInfo: BeaconInfo? = null, - @Json(name = "m.beacon_info") val beaconInfo: BeaconInfo? = null, + @Json(name = "description") val description: String? = null, + /** + * Beacon should be considered as inactive after this timeout as milliseconds. + */ + @Json(name = "timeout") val timeout: Long? = null, + /** + * Should be set true to start sharing beacon. + */ + @Json(name = "live") val isLive: Boolean? = null, + /** * Beacon creation timestamp. */ - @Json(name = "org.matrix.msc3488.ts") val unstableTimestampAsMilliseconds: Long? = null, - @Json(name = "m.ts") val timestampAsMilliseconds: Long? = null, + @Json(name = "org.matrix.msc3488.ts") val unstableTimestampMillis: Long? = null, + @Json(name = "m.ts") val timestampMillis: Long? = null, /** * Live location asset type. */ @Json(name = "org.matrix.msc3488.asset") val unstableLocationAsset: LocationAsset = LocationAsset(LocationAssetType.SELF), @Json(name = "m.asset") val locationAsset: LocationAsset? = null, - - /** - * Client side tracking of the last location - */ - var lastLocationContent: MessageLiveLocationContent? = null, - - /** - * Client side tracking of whether the beacon has timed out. - */ - var hasTimedOut: Boolean = false ) : MessageContent { - fun getBestBeaconInfo() = beaconInfo ?: unstableBeaconInfo - - fun getBestTimestampAsMilliseconds() = timestampAsMilliseconds ?: unstableTimestampAsMilliseconds + fun getBestTimestampMillis() = timestampMillis ?: unstableTimestampMillis fun getBestLocationAsset() = locationAsset ?: unstableLocationAsset } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageLiveLocationContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageBeaconLocationDataContent.kt similarity index 72% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageLiveLocationContent.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageBeaconLocationDataContent.kt index 548dc85369..4a4ef46bc8 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageLiveLocationContent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageBeaconLocationDataContent.kt @@ -21,13 +21,21 @@ import com.squareup.moshi.JsonClass import org.matrix.android.sdk.api.session.events.model.Content import org.matrix.android.sdk.api.session.room.model.relation.RelationDefaultContent +/** + * Content of the state event of type + * [EventType.BEACON_LOCATION_DATA][org.matrix.android.sdk.api.session.events.model.EventType.BEACON_LOCATION_DATA] + * + * It contains location data related to a live location share. + * It is related to the state event that originally started the live. + * See [MessageBeaconInfoContent][org.matrix.android.sdk.api.session.room.model.message.MessageBeaconInfoContent] + */ @JsonClass(generateAdapter = true) -data class MessageLiveLocationContent( +data class MessageBeaconLocationDataContent( /** * Local message type, not from server */ @Transient - override val msgType: String = MessageType.MSGTYPE_LIVE_LOCATION, + override val msgType: String = MessageType.MSGTYPE_BEACON_LOCATION_DATA, @Json(name = "body") override val body: String = "", @Json(name = "m.relates_to") override val relatesTo: RelationDefaultContent? = null, @@ -42,11 +50,11 @@ data class MessageLiveLocationContent( /** * Exact time that the data in the event refers to (milliseconds since the UNIX epoch) */ - @Json(name = "org.matrix.msc3488.ts") val unstableTimestampAsMilliseconds: Long? = null, - @Json(name = "m.ts") val timestampAsMilliseconds: Long? = null + @Json(name = "org.matrix.msc3488.ts") val unstableTimestampMillis: Long? = null, + @Json(name = "m.ts") val timestampMillis: Long? = null ) : MessageContent { fun getBestLocationInfo() = locationInfo ?: unstableLocationInfo - fun getBestTimestampAsMilliseconds() = timestampAsMilliseconds ?: unstableTimestampAsMilliseconds + fun getBestTimestampMillis() = timestampMillis ?: unstableTimestampMillis } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageLocationContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageLocationContent.kt index 2052133b06..19cb20430d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageLocationContent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageLocationContent.kt @@ -49,8 +49,8 @@ data class MessageLocationContent( /** * Exact time that the data in the event refers to (milliseconds since the UNIX epoch) */ - @Json(name = "org.matrix.msc3488.ts") val unstableTs: Long? = null, - @Json(name = "m.ts") val ts: Long? = null, + @Json(name = "org.matrix.msc3488.ts") val unstableTimestampMillis: Long? = null, + @Json(name = "m.ts") val timestampMillis: Long? = null, @Json(name = "org.matrix.msc1767.text") val unstableText: String? = null, @Json(name = "m.text") val text: String? = null, /** @@ -66,7 +66,7 @@ data class MessageLocationContent( fun getBestLocationInfo() = locationInfo ?: unstableLocationInfo - fun getBestTs() = ts ?: unstableTs + fun getBestTimestampMillis() = timestampMillis ?: unstableTimestampMillis fun getBestText() = text ?: unstableText diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageType.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageType.kt index 106bf2e030..b12d9ed6c8 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageType.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageType.kt @@ -41,6 +41,6 @@ object MessageType { const val MSGTYPE_SNOWFALL = "io.element.effect.snowfall" // Fake message types for live location events to be able to inherit them from MessageContent - const val MSGTYPE_LIVE_LOCATION_STATE = "org.matrix.android.sdk.livelocation.state" - const val MSGTYPE_LIVE_LOCATION = "org.matrix.android.sdk.livelocation" + const val MSGTYPE_BEACON_INFO = "org.matrix.android.sdk.beacon.info" + const val MSGTYPE_BEACON_LOCATION_DATA = "org.matrix.android.sdk.beacon.location.data" } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/state/StateService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/state/StateService.kt index f645f3ebf9..98171795e2 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/state/StateService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/state/StateService.kt @@ -84,8 +84,9 @@ interface StateService { * @param eventType The type of event to send. * @param stateKey The state_key for the state to send. Can be an empty string. * @param body The content object of the event; the fields in this object will vary depending on the type of event + * @return the id of the created state event */ - suspend fun sendStateEvent(eventType: String, stateKey: String, body: JsonDict) + suspend fun sendStateEvent(eventType: String, stateKey: String, body: JsonDict): String /** * Get a state event of the room diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineEvent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineEvent.kt index a2ae8bfeb5..adbc8ab12a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineEvent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineEvent.kt @@ -29,7 +29,7 @@ import org.matrix.android.sdk.api.session.events.model.isSticker import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.room.model.EventAnnotationsSummary import org.matrix.android.sdk.api.session.room.model.ReadReceipt -import org.matrix.android.sdk.api.session.room.model.livelocation.LiveLocationBeaconContent +import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconInfoContent import org.matrix.android.sdk.api.session.room.model.message.MessageContent import org.matrix.android.sdk.api.session.room.model.message.MessagePollContent import org.matrix.android.sdk.api.session.room.model.message.MessageStickerContent @@ -139,7 +139,7 @@ fun TimelineEvent.getLastMessageContent(): MessageContent? { return when (root.getClearType()) { EventType.STICKER -> root.getClearContent().toModel() in EventType.POLL_START -> (annotations?.editSummary?.latestContent ?: root.getClearContent()).toModel() - in EventType.STATE_ROOM_BEACON_INFO -> (annotations?.editSummary?.latestContent ?: root.getClearContent()).toModel() + in EventType.STATE_ROOM_BEACON_INFO -> (annotations?.editSummary?.latestContent ?: root.getClearContent()).toModel() else -> (annotations?.editSummary?.latestContent ?: root.getClearContent()).toModel() } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/SpaceService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/SpaceService.kt index 6d82b3f7df..afd26f7be5 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/SpaceService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/SpaceService.kt @@ -106,5 +106,8 @@ interface SpaceService { suspend fun removeSpaceParent(childRoomId: String, parentSpaceId: String) - fun getRootSpaceSummaries(): List + /** + * Get the root spaces, i.e. all the spaces which do not have a parent space. + */ + suspend fun getRootSpaceSummaries(): List } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/uia/UiaResult.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/uia/UiaResult.kt new file mode 100644 index 0000000000..ee4a180dea --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/uia/UiaResult.kt @@ -0,0 +1,23 @@ +/* + * Copyright 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.api.session.uia + +enum class UiaResult { + SUCCESS, + FAILURE, + CANCELLED +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/uia/exceptions/UiaCancelledException.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/uia/exceptions/UiaCancelledException.kt new file mode 100644 index 0000000000..d5f9d72efe --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/uia/exceptions/UiaCancelledException.kt @@ -0,0 +1,19 @@ +/* + * Copyright 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.api.session.uia.exceptions + +class UiaCancelledException(message: String? = null) : Exception(message) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/UIAExt.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/UIAExt.kt index da0866a5fd..7dafacb3c0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/UIAExt.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/UIAExt.kt @@ -20,6 +20,8 @@ import org.matrix.android.sdk.api.auth.UIABaseAuth import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor import org.matrix.android.sdk.api.failure.Failure import org.matrix.android.sdk.api.failure.toRegistrationFlowResponse +import org.matrix.android.sdk.api.session.uia.UiaResult +import org.matrix.android.sdk.api.session.uia.exceptions.UiaCancelledException import timber.log.Timber import kotlin.coroutines.suspendCoroutine @@ -30,14 +32,15 @@ import kotlin.coroutines.suspendCoroutine * @param interceptor see doc in [UserInteractiveAuthInterceptor] * @param retryBlock called at the end of the process, in this block generally retry executing the task, with * provided authUpdate - * @return true if UIA is handled without error + * @return UiaResult if UIA handled, failed or cancelled + * */ internal suspend fun handleUIA(failure: Throwable, interceptor: UserInteractiveAuthInterceptor, - retryBlock: suspend (UIABaseAuth) -> Unit): Boolean { + retryBlock: suspend (UIABaseAuth) -> Unit): UiaResult { Timber.d("## UIA: check error ${failure.message}") val flowResponse = failure.toRegistrationFlowResponse() - ?: return false.also { + ?: return UiaResult.FAILURE.also { Timber.d("## UIA: not a UIA error") } @@ -50,14 +53,19 @@ internal suspend fun handleUIA(failure: Throwable, interceptor.performStage(flowResponse, (failure as? Failure.ServerError)?.error?.code, continuation) } } catch (failure2: Throwable) { - Timber.w(failure2, "## UIA: failed to participate") - return false + return if (failure2 is UiaCancelledException) { + Timber.w(failure2, "## UIA: cancelled") + UiaResult.CANCELLED + } else { + Timber.w(failure2, "## UIA: failed to participate") + UiaResult.FAILURE + } } Timber.d("## UIA: updated auth") return try { retryBlock(authUpdate) - true + UiaResult.SUCCESS } catch (failure3: Throwable) { handleUIA(failure3, interceptor, retryBlock) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OlmSessionStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OlmSessionStore.kt index f4fbca6a0f..aac6f67aea 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OlmSessionStore.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OlmSessionStore.kt @@ -66,7 +66,8 @@ internal class OlmSessionStore @Inject constructor(private val store: IMXCryptoS olmSessions.getOrPut(deviceKey) { mutableListOf() }.forEach { cached -> getSafeSessionIdentifier(cached.olmSession)?.let { cachedSessionId -> if (!persistedKnownSessions.contains(cachedSessionId)) { - persistedKnownSessions.add(cachedSessionId) + // as it's in cache put in on top + persistedKnownSessions.add(0, cachedSessionId) } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/secrets/DefaultSharedSecretStorageService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/secrets/DefaultSharedSecretStorageService.kt index 972c03e92a..8c877593e7 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/secrets/DefaultSharedSecretStorageService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/secrets/DefaultSharedSecretStorageService.kt @@ -66,7 +66,7 @@ internal class DefaultSharedSecretStorageService @Inject constructor( key: SsssKeySpec?, keyName: String, keySigner: KeySigner?): SsssKeyCreationInfo { - return withContext(cryptoCoroutineScope.coroutineContext + coroutineDispatchers.main) { + return withContext(cryptoCoroutineScope.coroutineContext + coroutineDispatchers.computation) { val bytes = (key as? RawBytesKeySpec)?.privateKey ?: ByteArray(32).also { SecureRandom().nextBytes(it) @@ -99,7 +99,7 @@ internal class DefaultSharedSecretStorageService @Inject constructor( passphrase: String, keySigner: KeySigner, progressListener: ProgressListener?): SsssKeyCreationInfo { - return withContext(cryptoCoroutineScope.coroutineContext + coroutineDispatchers.main) { + return withContext(cryptoCoroutineScope.coroutineContext + coroutineDispatchers.computation) { val privatePart = generatePrivateKeyWithPassword(passphrase, progressListener) val storageKeyContent = SecretStorageKeyContent( @@ -158,7 +158,7 @@ internal class DefaultSharedSecretStorageService @Inject constructor( } override suspend fun storeSecret(name: String, secretBase64: String, keys: List) { - withContext(cryptoCoroutineScope.coroutineContext + coroutineDispatchers.main) { + withContext(cryptoCoroutineScope.coroutineContext + coroutineDispatchers.computation) { val encryptedContents = HashMap() keys.forEach { val keyId = it.keyId @@ -316,7 +316,7 @@ internal class DefaultSharedSecretStorageService @Inject constructor( val algorithm = key.keyInfo.content if (SSSS_ALGORITHM_CURVE25519_AES_SHA2 == algorithm.algorithm) { val keySpec = secretKey as? RawBytesKeySpec ?: throw SharedSecretStorageError.BadKeyFormat - return withContext(cryptoCoroutineScope.coroutineContext + coroutineDispatchers.main) { + return withContext(cryptoCoroutineScope.coroutineContext + coroutineDispatchers.computation) { // decrypt from recovery key withOlmDecryption { olmPkDecryption -> olmPkDecryption.setPrivateKey(keySpec.privateKey) @@ -331,7 +331,7 @@ internal class DefaultSharedSecretStorageService @Inject constructor( } } else if (SSSS_ALGORITHM_AES_HMAC_SHA2 == algorithm.algorithm) { val keySpec = secretKey as? RawBytesKeySpec ?: throw SharedSecretStorageError.BadKeyFormat - return withContext(cryptoCoroutineScope.coroutineContext + coroutineDispatchers.main) { + return withContext(cryptoCoroutineScope.coroutineContext + coroutineDispatchers.computation) { decryptAesHmacSha2(keySpec, name, secretContent) } } else { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt index 99adbbfbae..fad901f95d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt @@ -715,6 +715,7 @@ internal class RealmCryptoStore @Inject constructor( return doWithRealm(realmConfiguration) { it.where() .equalTo(OlmSessionEntityFields.DEVICE_KEY, deviceKey) + .sort(OlmSessionEntityFields.LAST_RECEIVED_MESSAGE_TS, Sort.DESCENDING) .findAll() .mapNotNull { sessionEntity -> sessionEntity.sessionId diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/DeleteDeviceTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/DeleteDeviceTask.kt index ca04bac5d5..0a77d33acc 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/DeleteDeviceTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/DeleteDeviceTask.kt @@ -18,6 +18,7 @@ package org.matrix.android.sdk.internal.crypto.tasks import org.matrix.android.sdk.api.auth.UIABaseAuth import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor +import org.matrix.android.sdk.api.session.uia.UiaResult import org.matrix.android.sdk.internal.auth.registration.handleUIA import org.matrix.android.sdk.internal.crypto.api.CryptoApi import org.matrix.android.sdk.internal.crypto.model.rest.DeleteDeviceParams @@ -47,13 +48,13 @@ internal class DefaultDeleteDeviceTask @Inject constructor( } } catch (throwable: Throwable) { if (params.userInteractiveAuthInterceptor == null || - !handleUIA( + handleUIA( failure = throwable, interceptor = params.userInteractiveAuthInterceptor, retryBlock = { authUpdate -> execute(params.copy(userAuthParam = authUpdate)) } - ) + ) != UiaResult.SUCCESS ) { Timber.d("## UIA: propagate failure") throw throwable diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/InitializeCrossSigningTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/InitializeCrossSigningTask.kt index eefdd25044..53190c43ff 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/InitializeCrossSigningTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/InitializeCrossSigningTask.kt @@ -20,6 +20,7 @@ import dagger.Lazy import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor import org.matrix.android.sdk.api.session.crypto.crosssigning.CryptoCrossSigningKey import org.matrix.android.sdk.api.session.crypto.crosssigning.KeyUsage +import org.matrix.android.sdk.api.session.uia.UiaResult import org.matrix.android.sdk.api.util.toBase64NoPadding import org.matrix.android.sdk.internal.auth.registration.handleUIA import org.matrix.android.sdk.internal.crypto.MXOlmDevice @@ -126,13 +127,13 @@ internal class DefaultInitializeCrossSigningTask @Inject constructor( uploadSigningKeysTask.execute(uploadSigningKeysParams) } catch (failure: Throwable) { if (params.interactiveAuthInterceptor == null || - !handleUIA( + handleUIA( failure = failure, interceptor = params.interactiveAuthInterceptor, retryBlock = { authUpdate -> uploadSigningKeysTask.execute(uploadSigningKeysParams.copy(userAuthParam = authUpdate)) } - ) + ) != UiaResult.SUCCESS ) { Timber.d("## UIA: propagate failure") throw failure diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/EventInsertLiveObserver.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/EventInsertLiveObserver.kt index b057b4c319..751992fa7f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/EventInsertLiveObserver.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/EventInsertLiveObserver.kt @@ -19,6 +19,9 @@ package org.matrix.android.sdk.internal.database import com.zhuinden.monarchy.Monarchy import io.realm.RealmConfiguration import io.realm.RealmResults +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import org.matrix.android.sdk.internal.database.mapper.asDomain import org.matrix.android.sdk.internal.database.model.EventEntity @@ -38,10 +41,22 @@ internal class EventInsertLiveObserver @Inject constructor(@SessionDatabase real it.where(EventInsertEntity::class.java).equalTo(EventInsertEntityFields.CAN_BE_PROCESSED, true) } + private val onResultsChangedFlow = MutableSharedFlow>() + + init { + onResultsChangedFlow + .onEach { handleChange(it) } + .launchIn(observerScope) + } + override fun onChange(results: RealmResults) { if (!results.isLoaded || results.isEmpty()) { return } + observerScope.launch { onResultsChangedFlow.emit(results) } + } + + private suspend fun handleChange(results: RealmResults) { val idsToDeleteAfterProcess = ArrayList() val filteredEvents = ArrayList(results.size) Timber.v("EventInsertEntity updated with ${results.size} results in db") @@ -58,30 +73,29 @@ internal class EventInsertLiveObserver @Inject constructor(@SessionDatabase real } idsToDeleteAfterProcess.add(it.eventId) } - observerScope.launch { - awaitTransaction(realmConfiguration) { realm -> - Timber.v("##Transaction: There are ${filteredEvents.size} events to process ") - filteredEvents.forEach { eventInsert -> - val eventId = eventInsert.eventId - val event = EventEntity.where(realm, eventId).findFirst() - if (event == null) { - Timber.v("Event $eventId not found") - return@forEach - } - val domainEvent = event.asDomain() - processors.filter { - it.shouldProcess(eventId, domainEvent.getClearType(), eventInsert.insertType) - }.forEach { - it.process(realm, domainEvent) - } + + awaitTransaction(realmConfiguration) { realm -> + Timber.v("##Transaction: There are ${filteredEvents.size} events to process ") + filteredEvents.forEach { eventInsert -> + val eventId = eventInsert.eventId + val event = EventEntity.where(realm, eventId).findFirst() + if (event == null) { + Timber.v("Event $eventId not found") + return@forEach + } + val domainEvent = event.asDomain() + processors.filter { + it.shouldProcess(eventId, domainEvent.getClearType(), eventInsert.insertType) + }.forEach { + it.process(realm, domainEvent) } - realm.where(EventInsertEntity::class.java) - .`in`(EventInsertEntityFields.EVENT_ID, idsToDeleteAfterProcess.toTypedArray()) - .findAll() - .deleteAllFromRealm() } - processors.forEach { it.onPostProcess() } + realm.where(EventInsertEntity::class.java) + .`in`(EventInsertEntityFields.EVENT_ID, idsToDeleteAfterProcess.toTypedArray()) + .findAll() + .deleteAllFromRealm() } + processors.forEach { it.onPostProcess() } } private fun shouldProcess(eventInsertEntity: EventInsertEntity): Boolean { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt index a57397dad5..24ac310653 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt @@ -44,6 +44,7 @@ import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo023 import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo024 import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo025 import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo026 +import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo027 import org.matrix.android.sdk.internal.util.Normalizer import timber.log.Timber import javax.inject.Inject @@ -58,7 +59,7 @@ internal class RealmSessionStoreMigration @Inject constructor( override fun equals(other: Any?) = other is RealmSessionStoreMigration override fun hashCode() = 1000 - val schemaVersion = 26L + val schemaVersion = 27L override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) { Timber.d("Migrating Realm Session from $oldVersion to $newVersion") @@ -89,5 +90,6 @@ internal class RealmSessionStoreMigration @Inject constructor( if (oldVersion < 24) MigrateSessionTo024(realm).perform() if (oldVersion < 25) MigrateSessionTo025(realm).perform() if (oldVersion < 26) MigrateSessionTo026(realm).perform() + if (oldVersion < 27) MigrateSessionTo027(realm).perform() } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ThreadSummaryHelper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ThreadSummaryHelper.kt index 24de26eeea..89474a1bc5 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ThreadSummaryHelper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ThreadSummaryHelper.kt @@ -20,6 +20,7 @@ import io.realm.Realm import io.realm.RealmQuery import io.realm.Sort import io.realm.kotlin.createObject +import kotlinx.coroutines.runBlocking import org.matrix.android.sdk.api.session.crypto.CryptoService import org.matrix.android.sdk.api.session.crypto.MXCryptoError import org.matrix.android.sdk.api.session.crypto.model.OlmDecryptionResult @@ -127,7 +128,7 @@ private fun EventEntity.toTimelineEventEntity(roomMemberContentsByUser: HashMap< return timelineEventEntity } -internal suspend fun ThreadSummaryEntity.Companion.createOrUpdate( +internal fun ThreadSummaryEntity.Companion.createOrUpdate( threadSummaryType: ThreadSummaryUpdateType, realm: Realm, roomId: String, @@ -153,10 +154,18 @@ internal suspend fun ThreadSummaryEntity.Companion.createOrUpdate( } val rootThreadEventEntity = createEventEntity(roomId, rootThreadEvent, realm).also { - decryptIfNeeded(cryptoService, it, roomId) + try { + decryptIfNeeded(cryptoService, it, roomId) + } catch (e: InterruptedException) { + Timber.i("Decryption got interrupted") + } } val latestThreadEventEntity = createLatestEventEntity(roomId, rootThreadEvent, roomMemberContentsByUser, realm)?.also { - decryptIfNeeded(cryptoService, it, roomId) + try { + decryptIfNeeded(cryptoService, it, roomId) + } catch (e: InterruptedException) { + Timber.i("Decryption got interrupted") + } } val isUserParticipating = rootThreadEvent.unsignedData.relations.latestThread.isUserParticipating == true || rootThreadEvent.senderId == userId roomMemberContentsByUser.addSenderState(realm, roomId, rootThreadEvent.senderId) @@ -204,14 +213,15 @@ internal suspend fun ThreadSummaryEntity.Companion.createOrUpdate( } } -private suspend fun decryptIfNeeded(cryptoService: CryptoService?, eventEntity: EventEntity, roomId: String) { +private fun decryptIfNeeded(cryptoService: CryptoService?, eventEntity: EventEntity, roomId: String) { cryptoService ?: return val event = eventEntity.asDomain() if (event.isEncrypted() && event.mxDecryptionResult == null && event.eventId != null) { try { Timber.i("###THREADS ThreadSummaryHelper request decryption for eventId:${event.eventId}") // Event from sync does not have roomId, so add it to the event first - val result = cryptoService.decryptEvent(event.copy(roomId = roomId), "") + // note: runBlocking should be used here while we are in realm single thread executor, to avoid thread switching + val result = runBlocking { cryptoService.decryptEvent(event.copy(roomId = roomId), "") } event.mxDecryptionResult = OlmDecryptionResult( payload = result.clearEvent, senderKey = result.senderCurve25519Key, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/EventAnnotationsSummaryMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/EventAnnotationsSummaryMapper.kt index 4a26b4c4bf..c747ad334f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/EventAnnotationsSummaryMapper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/EventAnnotationsSummaryMapper.kt @@ -25,7 +25,6 @@ import org.matrix.android.sdk.internal.database.model.EventAnnotationsSummaryEnt internal object EventAnnotationsSummaryMapper { fun map(annotationsSummary: EventAnnotationsSummaryEntity): EventAnnotationsSummary { return EventAnnotationsSummary( - eventId = annotationsSummary.eventId, reactionsSummary = annotationsSummary.reactionsSummary.toList().map { ReactionAggregatedSummary( it.key, @@ -50,7 +49,6 @@ internal object EventAnnotationsSummaryMapper { }, referencesAggregatedSummary = annotationsSummary.referencesSummaryEntity?.let { ReferencesAggregatedSummary( - it.eventId, ContentMapper.map(it.content), it.sourceEvents.toList(), it.sourceLocalEcho.toList() @@ -58,8 +56,10 @@ internal object EventAnnotationsSummaryMapper { }, pollResponseSummary = annotationsSummary.pollResponseSummary?.let { PollResponseAggregatedSummaryEntityMapper.map(it) + }, + liveLocationShareAggregatedSummary = annotationsSummary.liveLocationShareAggregatedSummary?.let { + LiveLocationShareAggregatedSummaryMapper.map(it) } - ) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/LiveLocationShareAggregatedSummaryMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/LiveLocationShareAggregatedSummaryMapper.kt new file mode 100644 index 0000000000..71b36f88bd --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/LiveLocationShareAggregatedSummaryMapper.kt @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.database.mapper + +import org.matrix.android.sdk.api.session.events.model.toModel +import org.matrix.android.sdk.api.session.room.model.livelocation.LiveLocationShareAggregatedSummary +import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconLocationDataContent +import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntity + +internal object LiveLocationShareAggregatedSummaryMapper { + + fun map(entity: LiveLocationShareAggregatedSummaryEntity): LiveLocationShareAggregatedSummary { + return LiveLocationShareAggregatedSummary( + isActive = entity.isActive, + endOfLiveTimestampMillis = entity.endOfLiveTimestampMillis, + lastLocationDataContent = ContentMapper.map(entity.lastLocationContent).toModel() + ) + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/PushConditionMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/PushConditionMapper.kt index 5c0a2ba902..6521bf62d9 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/PushConditionMapper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/PushConditionMapper.kt @@ -16,7 +16,7 @@ package org.matrix.android.sdk.internal.database.mapper -import org.matrix.android.sdk.api.pushrules.rest.PushCondition +import org.matrix.android.sdk.api.session.pushrules.rest.PushCondition import org.matrix.android.sdk.internal.database.model.PushConditionEntity internal object PushConditionMapper { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/PushRulesMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/PushRulesMapper.kt index 12eff8efa1..0b07754126 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/PushRulesMapper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/PushRulesMapper.kt @@ -17,9 +17,9 @@ package org.matrix.android.sdk.internal.database.mapper import com.squareup.moshi.Types import io.realm.RealmList -import org.matrix.android.sdk.api.pushrules.Kind -import org.matrix.android.sdk.api.pushrules.rest.PushCondition -import org.matrix.android.sdk.api.pushrules.rest.PushRule +import org.matrix.android.sdk.api.session.pushrules.Kind +import org.matrix.android.sdk.api.session.pushrules.rest.PushCondition +import org.matrix.android.sdk.api.session.pushrules.rest.PushRule import org.matrix.android.sdk.internal.database.model.PushRuleEntity import org.matrix.android.sdk.internal.di.MoshiProvider import timber.log.Timber diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo027.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo027.kt new file mode 100644 index 0000000000..fdd8c46d02 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo027.kt @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.database.migration + +import io.realm.DynamicRealm +import io.realm.FieldAttribute +import org.matrix.android.sdk.internal.database.model.EventAnnotationsSummaryEntityFields +import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntityFields +import org.matrix.android.sdk.internal.util.database.RealmMigrator + +/** + * Migrating to: + * Live location sharing aggregated summary + */ +internal class MigrateSessionTo027(realm: DynamicRealm) : RealmMigrator(realm, 27) { + + override fun doMigrate(realm: DynamicRealm) { + val liveLocationSummaryEntity = realm.schema.get("LiveLocationShareAggregatedSummaryEntity") + ?: realm.schema.create("LiveLocationShareAggregatedSummaryEntity") + .addField(LiveLocationShareAggregatedSummaryEntityFields.EVENT_ID, String::class.java, FieldAttribute.REQUIRED) + .addField(LiveLocationShareAggregatedSummaryEntityFields.ROOM_ID, String::class.java, FieldAttribute.REQUIRED) + .addField(LiveLocationShareAggregatedSummaryEntityFields.IS_ACTIVE, Boolean::class.java) + .setNullable(LiveLocationShareAggregatedSummaryEntityFields.IS_ACTIVE, true) + .addField(LiveLocationShareAggregatedSummaryEntityFields.END_OF_LIVE_TIMESTAMP_MILLIS, Long::class.java) + .setNullable(LiveLocationShareAggregatedSummaryEntityFields.END_OF_LIVE_TIMESTAMP_MILLIS, true) + .addField(LiveLocationShareAggregatedSummaryEntityFields.LAST_LOCATION_CONTENT, String::class.java) + ?: return + + realm.schema.get("EventAnnotationsSummaryEntity") + ?.addRealmObjectField(EventAnnotationsSummaryEntityFields.LIVE_LOCATION_SHARE_AGGREGATED_SUMMARY.`$`, liveLocationSummaryEntity) + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/EventAnnotationsSummaryEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/EventAnnotationsSummaryEntity.kt index 3e88130420..c3abd8b028 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/EventAnnotationsSummaryEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/EventAnnotationsSummaryEntity.kt @@ -18,6 +18,7 @@ package org.matrix.android.sdk.internal.database.model import io.realm.RealmList import io.realm.RealmObject import io.realm.annotations.PrimaryKey +import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntity import timber.log.Timber internal open class EventAnnotationsSummaryEntity( @@ -27,7 +28,8 @@ internal open class EventAnnotationsSummaryEntity( var reactionsSummary: RealmList = RealmList(), var editSummary: EditAggregatedSummaryEntity? = null, var referencesSummaryEntity: ReferencesAggregatedSummaryEntity? = null, - var pollResponseSummary: PollResponseAggregatedSummaryEntity? = null + var pollResponseSummary: PollResponseAggregatedSummaryEntity? = null, + var liveLocationShareAggregatedSummary: LiveLocationShareAggregatedSummaryEntity? = null, ) : RealmObject() { /** diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/PushRulesEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/PushRulesEntity.kt index 4125d90891..62bf40c1d2 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/PushRulesEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/PushRulesEntity.kt @@ -17,7 +17,7 @@ package org.matrix.android.sdk.internal.database.model import io.realm.RealmList import io.realm.RealmObject -import org.matrix.android.sdk.api.pushrules.RuleKind +import org.matrix.android.sdk.api.session.pushrules.RuleKind import org.matrix.android.sdk.internal.extensions.clearWith internal open class PushRulesEntity( diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/SessionRealmModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/SessionRealmModule.kt index d0d23dd491..9a92b14510 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/SessionRealmModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/SessionRealmModule.kt @@ -17,6 +17,7 @@ package org.matrix.android.sdk.internal.database.model import io.realm.annotations.RealmModule +import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntity import org.matrix.android.sdk.internal.database.model.presence.UserPresenceEntity import org.matrix.android.sdk.internal.database.model.threads.ThreadSummaryEntity @@ -47,6 +48,7 @@ import org.matrix.android.sdk.internal.database.model.threads.ThreadSummaryEntit EditAggregatedSummaryEntity::class, EditionOfEvent::class, PollResponseAggregatedSummaryEntity::class, + LiveLocationShareAggregatedSummaryEntity::class, ReferencesAggregatedSummaryEntity::class, PushRulesEntity::class, PushRuleEntity::class, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/livelocation/LiveLocationShareAggregatedSummaryEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/livelocation/LiveLocationShareAggregatedSummaryEntity.kt new file mode 100644 index 0000000000..1376839f93 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/livelocation/LiveLocationShareAggregatedSummaryEntity.kt @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.database.model.livelocation + +import io.realm.RealmObject +import io.realm.annotations.PrimaryKey + +/** + * Aggregation info concerning a live location share. + */ +internal open class LiveLocationShareAggregatedSummaryEntity( + /** + * Event id of the event that started the live. + */ + @PrimaryKey + var eventId: String = "", + + var roomId: String = "", + + var isActive: Boolean? = null, + + var endOfLiveTimestampMillis: Long? = null, + + /** + * For now we persist this as a JSON for greater flexibility + * @see [org.matrix.android.sdk.api.session.room.model.message.MessageBeaconLocationDataContent] + */ + var lastLocationContent: String? = null, +) : RealmObject() { + companion object +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/LiveLocationShareAggregatedSummaryEntityQuery.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/LiveLocationShareAggregatedSummaryEntityQuery.kt new file mode 100644 index 0000000000..2e2e939fa2 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/LiveLocationShareAggregatedSummaryEntityQuery.kt @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.database.query + +import io.realm.Realm +import io.realm.RealmQuery +import io.realm.kotlin.where +import org.matrix.android.sdk.internal.database.model.EventAnnotationsSummaryEntity +import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntity +import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntityFields + +internal fun LiveLocationShareAggregatedSummaryEntity.Companion.where( + realm: Realm, + roomId: String, + eventId: String, +): RealmQuery { + return realm.where() + .equalTo(LiveLocationShareAggregatedSummaryEntityFields.ROOM_ID, roomId) + .equalTo(LiveLocationShareAggregatedSummaryEntityFields.EVENT_ID, eventId) +} + +internal fun LiveLocationShareAggregatedSummaryEntity.Companion.create( + realm: Realm, + roomId: String, + eventId: String, +): LiveLocationShareAggregatedSummaryEntity { + val obj = realm.createObject(LiveLocationShareAggregatedSummaryEntity::class.java, eventId).apply { + this.roomId = roomId + } + val annotationSummary = EventAnnotationsSummaryEntity.getOrCreate(realm, roomId = roomId, eventId = eventId) + annotationSummary.liveLocationShareAggregatedSummary = obj + + return obj +} + +internal fun LiveLocationShareAggregatedSummaryEntity.Companion.getOrCreate( + realm: Realm, + roomId: String, + eventId: String, +): LiveLocationShareAggregatedSummaryEntity { + return LiveLocationShareAggregatedSummaryEntity.where(realm, roomId, eventId).findFirst() + ?: LiveLocationShareAggregatedSummaryEntity.create(realm, roomId, eventId) +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/PushersQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/PushersQueries.kt index 1f6b210252..3cea19a690 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/PushersQueries.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/PushersQueries.kt @@ -18,7 +18,7 @@ package org.matrix.android.sdk.internal.database.query import io.realm.Realm import io.realm.RealmQuery import io.realm.kotlin.where -import org.matrix.android.sdk.api.pushrules.RuleKind +import org.matrix.android.sdk.api.session.pushrules.RuleKind import org.matrix.android.sdk.internal.database.model.PushRuleEntity import org.matrix.android.sdk.internal.database.model.PushRuleEntityFields import org.matrix.android.sdk.internal.database.model.PushRulesEntity diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt index 1e533158a7..5f77cfb23a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt @@ -26,7 +26,6 @@ import org.matrix.android.sdk.api.MatrixCoroutineDispatchers import org.matrix.android.sdk.api.auth.data.SessionParams import org.matrix.android.sdk.api.failure.GlobalError import org.matrix.android.sdk.api.federation.FederationService -import org.matrix.android.sdk.api.pushrules.PushRuleService import org.matrix.android.sdk.api.session.EventStreamService import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.SessionLifecycleObserver @@ -53,6 +52,7 @@ import org.matrix.android.sdk.api.session.permalinks.PermalinkService import org.matrix.android.sdk.api.session.presence.PresenceService import org.matrix.android.sdk.api.session.profile.ProfileService import org.matrix.android.sdk.api.session.pushers.PushersService +import org.matrix.android.sdk.api.session.pushrules.PushRuleService import org.matrix.android.sdk.api.session.room.RoomDirectoryService import org.matrix.android.sdk.api.session.room.RoomService import org.matrix.android.sdk.api.session.search.SearchService @@ -124,12 +124,12 @@ internal class DefaultSession @Inject constructor( private val syncStatusService: Lazy, private val homeServerCapabilitiesService: Lazy, private val accountDataService: Lazy, - private val _sharedSecretStorageService: Lazy, + private val sharedSecretStorageService: Lazy, private val accountService: Lazy, private val eventService: Lazy, private val contentScannerService: Lazy, - private val identityService: IdentityService, - private val integrationManagerService: IntegrationManagerService, + private val identityService: Lazy, + private val integrationManagerService: Lazy, private val thirdPartyService: Lazy, private val callSignalingService: Lazy, private val spaceService: Lazy, @@ -140,28 +140,7 @@ internal class DefaultSession @Inject constructor( @UnauthenticatedWithCertificate private val unauthenticatedWithCertificateOkHttpClient: Lazy ) : Session, - GlobalErrorHandler.Listener, - RoomService by roomService.get(), - RoomDirectoryService by roomDirectoryService.get(), - GroupService by groupService.get(), - UserService by userService.get(), - SignOutService by signOutService.get(), - FilterService by filterService.get(), - PushRuleService by pushRuleService.get(), - PushersService by pushersService.get(), - EventService by eventService.get(), - TermsService by termsService.get(), - SyncStatusService by syncStatusService.get(), - SecureStorageService by secureStorageService.get(), - HomeServerCapabilitiesService by homeServerCapabilitiesService.get(), - ProfileService by profileService.get(), - PresenceService by presenceService.get(), - AccountService by accountService.get(), - ToDeviceService by toDeviceService.get(), - EventStreamService by eventStreamService.get() { - - override val sharedSecretStorageService: SharedSecretStorageService - get() = _sharedSecretStorageService.get() + GlobalErrorHandler.Listener { private var isOpen = false @@ -274,42 +253,44 @@ internal class DefaultSession @Inject constructor( } override fun contentUrlResolver() = contentUrlResolver - override fun contentUploadProgressTracker() = contentUploadProgressTracker - override fun typingUsersTracker() = typingUsersTracker - override fun contentDownloadProgressTracker(): ContentDownloadStateTracker = contentDownloadStateTracker override fun cryptoService(): CryptoService = cryptoService.get() - override fun contentScannerService(): ContentScannerService = contentScannerService.get() - - override fun identityService() = identityService - + override fun identityService(): IdentityService = identityService.get() + override fun homeServerCapabilitiesService(): HomeServerCapabilitiesService = homeServerCapabilitiesService.get() + override fun roomService(): RoomService = roomService.get() + override fun roomDirectoryService(): RoomDirectoryService = roomDirectoryService.get() + override fun groupService(): GroupService = groupService.get() + override fun userService(): UserService = userService.get() + override fun signOutService(): SignOutService = signOutService.get() + override fun filterService(): FilterService = filterService.get() + override fun pushRuleService(): PushRuleService = pushRuleService.get() + override fun pushersService(): PushersService = pushersService.get() + override fun eventService(): EventService = eventService.get() + override fun termsService(): TermsService = termsService.get() + override fun syncStatusService(): SyncStatusService = syncStatusService.get() + override fun secureStorageService(): SecureStorageService = secureStorageService.get() + override fun profileService(): ProfileService = profileService.get() + override fun presenceService(): PresenceService = presenceService.get() + override fun accountService(): AccountService = accountService.get() + override fun toDeviceService(): ToDeviceService = toDeviceService.get() + override fun eventStreamService(): EventStreamService = eventStreamService.get() override fun fileService(): FileService = defaultFileService.get() - override fun permalinkService(): PermalinkService = permalinkService.get() - override fun widgetService(): WidgetService = widgetService.get() - override fun mediaService(): MediaService = mediaService.get() - - override fun integrationManagerService() = integrationManagerService - + override fun integrationManagerService(): IntegrationManagerService = integrationManagerService.get() override fun callSignalingService(): CallSignalingService = callSignalingService.get() - override fun searchService(): SearchService = searchService.get() - override fun federationService(): FederationService = federationService.get() - override fun thirdPartyService(): ThirdPartyService = thirdPartyService.get() - override fun spaceService(): SpaceService = spaceService.get() - override fun openIdService(): OpenIdService = openIdService.get() - override fun accountDataService(): SessionAccountDataService = accountDataService.get() + override fun sharedSecretStorageService(): SharedSecretStorageService = sharedSecretStorageService.get() override fun getOkHttpClient(): OkHttpClient { return unauthenticatedWithCertificateOkHttpClient.get() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/DeactivateAccountTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/DeactivateAccountTask.kt index 752856b931..9f3f1f649e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/DeactivateAccountTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/DeactivateAccountTask.kt @@ -18,6 +18,8 @@ package org.matrix.android.sdk.internal.session.account import org.matrix.android.sdk.api.auth.UIABaseAuth import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor +import org.matrix.android.sdk.api.session.uia.UiaResult +import org.matrix.android.sdk.api.session.uia.exceptions.UiaCancelledException import org.matrix.android.sdk.internal.auth.registration.handleUIA import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest @@ -51,18 +53,24 @@ internal class DefaultDeactivateAccountTask @Inject constructor( } true } catch (throwable: Throwable) { - if (!handleUIA( - failure = throwable, - interceptor = params.userInteractiveAuthInterceptor, - retryBlock = { authUpdate -> - execute(params.copy(userAuthParam = authUpdate)) - } - ) - ) { - Timber.d("## UIA: propagate failure") - throw throwable - } else { - false + when (handleUIA( + failure = throwable, + interceptor = params.userInteractiveAuthInterceptor, + retryBlock = { authUpdate -> + execute(params.copy(userAuthParam = authUpdate)) + } + )) { + UiaResult.SUCCESS -> { + false + } + UiaResult.FAILURE -> { + Timber.d("## UIA: propagate failure") + throw throwable + } + UiaResult.CANCELLED -> { + Timber.d("## UIA: cancelled") + throw UiaCancelledException() + } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/ViaParameterFinder.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/ViaParameterFinder.kt index dff82cb42e..d20cf8f140 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/ViaParameterFinder.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/ViaParameterFinder.kt @@ -72,6 +72,7 @@ internal class ViaParameterFinder @Inject constructor( */ private fun getUserIdsOfJoinedMembers(roomId: String): Set { return roomGetterProvider.get().getRoom(roomId) + ?.membershipService() ?.getRoomMembers(roomMemberQueryParams { memberships = listOf(Membership.JOIN) }) ?.map { it.userId } .orEmpty() @@ -84,6 +85,7 @@ internal class ViaParameterFinder @Inject constructor( // It may not be possible for a user to join a room if there's no overlap between these fun computeViaParamsForRestricted(roomId: String, max: Int): List { val userThatCanInvite = roomGetterProvider.get().getRoom(roomId) + ?.membershipService() ?.getRoomMembers(roomMemberQueryParams { memberships = listOf(Membership.JOIN) }) ?.map { it.userId } ?.filter { userCanInvite(userId, roomId) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/FinalizeAddingThreePidTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/FinalizeAddingThreePidTask.kt index 6ff4efaf11..501aff63bd 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/FinalizeAddingThreePidTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/FinalizeAddingThreePidTask.kt @@ -22,6 +22,7 @@ import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor import org.matrix.android.sdk.api.failure.Failure import org.matrix.android.sdk.api.failure.toRegistrationFlowResponse import org.matrix.android.sdk.api.session.identity.ThreePid +import org.matrix.android.sdk.api.session.uia.UiaResult import org.matrix.android.sdk.internal.auth.registration.handleUIA import org.matrix.android.sdk.internal.database.model.PendingThreePidEntity import org.matrix.android.sdk.internal.database.model.PendingThreePidEntityFields @@ -72,13 +73,13 @@ internal class DefaultFinalizeAddingThreePidTask @Inject constructor( true } catch (throwable: Throwable) { if (params.userInteractiveAuthInterceptor == null || - !handleUIA( + handleUIA( failure = throwable, interceptor = params.userInteractiveAuthInterceptor, retryBlock = { authUpdate -> execute(params.copy(userAuthParam = authUpdate)) } - ) + ) != UiaResult.SUCCESS ) { Timber.d("## UIA: propagate failure") throw throwable.toRegistrationFlowResponse() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/AddPushRuleTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/AddPushRuleTask.kt index b217687168..c46474cf90 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/AddPushRuleTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/AddPushRuleTask.kt @@ -15,8 +15,8 @@ */ package org.matrix.android.sdk.internal.session.pushers -import org.matrix.android.sdk.api.pushrules.RuleKind -import org.matrix.android.sdk.api.pushrules.rest.PushRule +import org.matrix.android.sdk.api.session.pushrules.RuleKind +import org.matrix.android.sdk.api.session.pushrules.rest.PushRule import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/DefaultConditionResolver.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/DefaultConditionResolver.kt index 84a05067be..67fba390d0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/DefaultConditionResolver.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/DefaultConditionResolver.kt @@ -15,14 +15,15 @@ */ package org.matrix.android.sdk.internal.session.pushers -import org.matrix.android.sdk.api.pushrules.ConditionResolver -import org.matrix.android.sdk.api.pushrules.ContainsDisplayNameCondition -import org.matrix.android.sdk.api.pushrules.EventMatchCondition -import org.matrix.android.sdk.api.pushrules.RoomMemberCountCondition -import org.matrix.android.sdk.api.pushrules.SenderNotificationPermissionCondition import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.toModel +import org.matrix.android.sdk.api.session.pushrules.ConditionResolver +import org.matrix.android.sdk.api.session.pushrules.ContainsDisplayNameCondition +import org.matrix.android.sdk.api.session.pushrules.EventMatchCondition +import org.matrix.android.sdk.api.session.pushrules.RoomMemberCountCondition +import org.matrix.android.sdk.api.session.pushrules.SenderNotificationPermissionCondition +import org.matrix.android.sdk.api.session.room.getStateEvent import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent import org.matrix.android.sdk.internal.di.UserId import org.matrix.android.sdk.internal.session.room.RoomGetter @@ -60,7 +61,7 @@ internal class DefaultConditionResolver @Inject constructor( condition: ContainsDisplayNameCondition): Boolean { val roomId = event.roomId ?: return false val room = roomGetter.getRoom(roomId) ?: return false - val myDisplayName = room.getRoomMember(userId)?.displayName ?: return false + val myDisplayName = room.membershipService().getRoomMember(userId)?.displayName ?: return false return condition.isSatisfied(event, myDisplayName) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/rest/GetPushRulesResponse.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/GetPushRulesResponse.kt similarity index 90% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/rest/GetPushRulesResponse.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/GetPushRulesResponse.kt index 35b4d77c0e..de03819629 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/rest/GetPushRulesResponse.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/GetPushRulesResponse.kt @@ -13,10 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.matrix.android.sdk.api.pushrules.rest +package org.matrix.android.sdk.internal.session.pushers import com.squareup.moshi.Json import com.squareup.moshi.JsonClass +import org.matrix.android.sdk.api.session.pushrules.rest.RuleSet /** * All push rulesets for a user. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/PushRulesApi.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/PushRulesApi.kt index 994b4860c6..dab6d37317 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/PushRulesApi.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/PushRulesApi.kt @@ -15,8 +15,7 @@ */ package org.matrix.android.sdk.internal.session.pushers -import org.matrix.android.sdk.api.pushrules.rest.GetPushRulesResponse -import org.matrix.android.sdk.api.pushrules.rest.PushRule +import org.matrix.android.sdk.api.session.pushrules.rest.PushRule import org.matrix.android.sdk.internal.network.NetworkConstants import retrofit2.http.Body import retrofit2.http.DELETE diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/PushersModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/PushersModule.kt index d53a4eed65..4528c95e69 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/PushersModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/PushersModule.kt @@ -19,14 +19,14 @@ package org.matrix.android.sdk.internal.session.pushers import dagger.Binds import dagger.Module import dagger.Provides -import org.matrix.android.sdk.api.pushrules.ConditionResolver -import org.matrix.android.sdk.api.pushrules.PushRuleService import org.matrix.android.sdk.api.session.pushers.PushersService -import org.matrix.android.sdk.internal.session.notification.DefaultProcessEventForPushTask -import org.matrix.android.sdk.internal.session.notification.DefaultPushRuleService -import org.matrix.android.sdk.internal.session.notification.ProcessEventForPushTask +import org.matrix.android.sdk.api.session.pushrules.ConditionResolver +import org.matrix.android.sdk.api.session.pushrules.PushRuleService import org.matrix.android.sdk.internal.session.pushers.gateway.DefaultPushGatewayNotifyTask import org.matrix.android.sdk.internal.session.pushers.gateway.PushGatewayNotifyTask +import org.matrix.android.sdk.internal.session.pushrules.DefaultProcessEventForPushTask +import org.matrix.android.sdk.internal.session.pushrules.DefaultPushRuleService +import org.matrix.android.sdk.internal.session.pushrules.ProcessEventForPushTask import org.matrix.android.sdk.internal.session.room.notification.DefaultSetRoomNotificationStateTask import org.matrix.android.sdk.internal.session.room.notification.SetRoomNotificationStateTask import retrofit2.Retrofit diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/RemovePushRuleTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/RemovePushRuleTask.kt index bae893608b..9b0bf7934b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/RemovePushRuleTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/RemovePushRuleTask.kt @@ -15,7 +15,7 @@ */ package org.matrix.android.sdk.internal.session.pushers -import org.matrix.android.sdk.api.pushrules.RuleKind +import org.matrix.android.sdk.api.session.pushrules.RuleKind import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/SavePushRulesTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/SavePushRulesTask.kt index 6a4b891ecf..ff685e9281 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/SavePushRulesTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/SavePushRulesTask.kt @@ -16,9 +16,8 @@ package org.matrix.android.sdk.internal.session.pushers import com.zhuinden.monarchy.Monarchy -import org.matrix.android.sdk.api.pushrules.RuleScope -import org.matrix.android.sdk.api.pushrules.RuleSetKey -import org.matrix.android.sdk.api.pushrules.rest.GetPushRulesResponse +import org.matrix.android.sdk.api.session.pushrules.RuleScope +import org.matrix.android.sdk.api.session.pushrules.RuleSetKey import org.matrix.android.sdk.internal.database.mapper.PushRulesMapper import org.matrix.android.sdk.internal.database.model.PushRulesEntity import org.matrix.android.sdk.internal.database.model.deleteOnCascade diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/UpdatePushRuleActionsTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/UpdatePushRuleActionsTask.kt index 56f92d7b66..454b9cdd80 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/UpdatePushRuleActionsTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/UpdatePushRuleActionsTask.kt @@ -15,9 +15,9 @@ */ package org.matrix.android.sdk.internal.session.pushers -import org.matrix.android.sdk.api.pushrules.Action -import org.matrix.android.sdk.api.pushrules.RuleKind -import org.matrix.android.sdk.api.pushrules.toJson +import org.matrix.android.sdk.api.session.pushrules.Action +import org.matrix.android.sdk.api.session.pushrules.RuleKind +import org.matrix.android.sdk.api.session.pushrules.toJson import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/UpdatePushRuleEnableStatusTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/UpdatePushRuleEnableStatusTask.kt index 3fe1614678..815661a1ce 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/UpdatePushRuleEnableStatusTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/UpdatePushRuleEnableStatusTask.kt @@ -15,8 +15,8 @@ */ package org.matrix.android.sdk.internal.session.pushers -import org.matrix.android.sdk.api.pushrules.RuleKind -import org.matrix.android.sdk.api.pushrules.rest.PushRule +import org.matrix.android.sdk.api.session.pushrules.RuleKind +import org.matrix.android.sdk.api.session.pushrules.rest.PushRule import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/notification/DefaultPushRuleService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushrules/DefaultPushRuleService.kt similarity index 90% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/notification/DefaultPushRuleService.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushrules/DefaultPushRuleService.kt index cdc7350f8b..ace23f1fe5 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/notification/DefaultPushRuleService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushrules/DefaultPushRuleService.kt @@ -13,23 +13,23 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.matrix.android.sdk.internal.session.notification +package org.matrix.android.sdk.internal.session.pushrules import androidx.lifecycle.LiveData import androidx.lifecycle.Transformations import com.zhuinden.monarchy.Monarchy -import org.matrix.android.sdk.api.pushrules.Action -import org.matrix.android.sdk.api.pushrules.ConditionResolver -import org.matrix.android.sdk.api.pushrules.PushEvents -import org.matrix.android.sdk.api.pushrules.PushRuleService -import org.matrix.android.sdk.api.pushrules.RuleKind -import org.matrix.android.sdk.api.pushrules.RuleScope -import org.matrix.android.sdk.api.pushrules.RuleSetKey -import org.matrix.android.sdk.api.pushrules.SenderNotificationPermissionCondition -import org.matrix.android.sdk.api.pushrules.getActions -import org.matrix.android.sdk.api.pushrules.rest.PushRule -import org.matrix.android.sdk.api.pushrules.rest.RuleSet import org.matrix.android.sdk.api.session.events.model.Event +import org.matrix.android.sdk.api.session.pushrules.Action +import org.matrix.android.sdk.api.session.pushrules.ConditionResolver +import org.matrix.android.sdk.api.session.pushrules.PushEvents +import org.matrix.android.sdk.api.session.pushrules.PushRuleService +import org.matrix.android.sdk.api.session.pushrules.RuleKind +import org.matrix.android.sdk.api.session.pushrules.RuleScope +import org.matrix.android.sdk.api.session.pushrules.RuleSetKey +import org.matrix.android.sdk.api.session.pushrules.SenderNotificationPermissionCondition +import org.matrix.android.sdk.api.session.pushrules.getActions +import org.matrix.android.sdk.api.session.pushrules.rest.PushRule +import org.matrix.android.sdk.api.session.pushrules.rest.RuleSet import org.matrix.android.sdk.internal.database.mapper.PushRulesMapper import org.matrix.android.sdk.internal.database.model.PushRuleEntity import org.matrix.android.sdk.internal.database.model.PushRulesEntity diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/notification/ProcessEventForPushTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushrules/ProcessEventForPushTask.kt similarity index 95% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/notification/ProcessEventForPushTask.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushrules/ProcessEventForPushTask.kt index 899bce4c8d..91d092a2b4 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/notification/ProcessEventForPushTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushrules/ProcessEventForPushTask.kt @@ -14,12 +14,12 @@ * limitations under the License. */ -package org.matrix.android.sdk.internal.session.notification +package org.matrix.android.sdk.internal.session.pushrules -import org.matrix.android.sdk.api.pushrules.PushEvents -import org.matrix.android.sdk.api.pushrules.rest.PushRule import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.isInvitation +import org.matrix.android.sdk.api.session.pushrules.PushEvents +import org.matrix.android.sdk.api.session.pushrules.rest.PushRule import org.matrix.android.sdk.api.session.sync.model.RoomsSyncResponse import org.matrix.android.sdk.internal.di.UserId import org.matrix.android.sdk.internal.task.Task diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/notification/PushRuleFinder.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushrules/PushRuleFinder.kt similarity index 86% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/notification/PushRuleFinder.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushrules/PushRuleFinder.kt index 6e302d373d..b9d06a934d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/notification/PushRuleFinder.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushrules/PushRuleFinder.kt @@ -14,11 +14,11 @@ * limitations under the License. */ -package org.matrix.android.sdk.internal.session.notification +package org.matrix.android.sdk.internal.session.pushrules -import org.matrix.android.sdk.api.pushrules.ConditionResolver -import org.matrix.android.sdk.api.pushrules.rest.PushRule import org.matrix.android.sdk.api.session.events.model.Event +import org.matrix.android.sdk.api.session.pushrules.ConditionResolver +import org.matrix.android.sdk.api.session.pushrules.rest.PushRule import javax.inject.Inject internal class PushRuleFinder @Inject constructor( diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoom.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoom.kt index 3f129c4d71..7326adee4c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoom.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoom.kt @@ -18,13 +18,11 @@ package org.matrix.android.sdk.internal.session.room import androidx.lifecycle.LiveData import org.matrix.android.sdk.api.MatrixCoroutineDispatchers -import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM -import org.matrix.android.sdk.api.session.crypto.CryptoService -import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.room.Room import org.matrix.android.sdk.api.session.room.accountdata.RoomAccountDataService import org.matrix.android.sdk.api.session.room.alias.AliasService import org.matrix.android.sdk.api.session.room.call.RoomCallService +import org.matrix.android.sdk.api.session.room.crypto.RoomCryptoService import org.matrix.android.sdk.api.session.room.members.MembershipService import org.matrix.android.sdk.api.session.room.model.RoomSummary import org.matrix.android.sdk.api.session.room.model.RoomType @@ -42,62 +40,37 @@ import org.matrix.android.sdk.api.session.room.timeline.TimelineService import org.matrix.android.sdk.api.session.room.typing.TypingService import org.matrix.android.sdk.api.session.room.uploads.UploadsService import org.matrix.android.sdk.api.session.room.version.RoomVersionService -import org.matrix.android.sdk.api.session.search.SearchResult import org.matrix.android.sdk.api.session.space.Space import org.matrix.android.sdk.api.util.Optional -import org.matrix.android.sdk.api.util.awaitCallback import org.matrix.android.sdk.internal.session.permalinks.ViaParameterFinder -import org.matrix.android.sdk.internal.session.room.state.SendStateTask import org.matrix.android.sdk.internal.session.room.summary.RoomSummaryDataSource -import org.matrix.android.sdk.internal.session.search.SearchTask import org.matrix.android.sdk.internal.session.space.DefaultSpace -import java.security.InvalidParameterException -internal class DefaultRoom(override val roomId: String, - private val roomSummaryDataSource: RoomSummaryDataSource, - private val timelineService: TimelineService, - private val threadsService: ThreadsService, - private val threadsLocalService: ThreadsLocalService, - private val sendService: SendService, - private val draftService: DraftService, - private val stateService: StateService, - private val uploadsService: UploadsService, - private val reportingService: ReportingService, - private val roomCallService: RoomCallService, - private val readService: ReadService, - private val typingService: TypingService, - private val aliasService: AliasService, - private val tagsService: TagsService, - private val cryptoService: CryptoService, - private val relationService: RelationService, - private val roomMembersService: MembershipService, - private val roomPushRuleService: RoomPushRuleService, - private val roomAccountDataService: RoomAccountDataService, - private val roomVersionService: RoomVersionService, - private val sendStateTask: SendStateTask, - private val viaParameterFinder: ViaParameterFinder, - private val searchTask: SearchTask, - override val coroutineDispatchers: MatrixCoroutineDispatchers -) : - Room, - TimelineService by timelineService, - ThreadsService by threadsService, - ThreadsLocalService by threadsLocalService, - SendService by sendService, - DraftService by draftService, - StateService by stateService, - UploadsService by uploadsService, - ReportingService by reportingService, - RoomCallService by roomCallService, - ReadService by readService, - TypingService by typingService, - AliasService by aliasService, - TagsService by tagsService, - RelationService by relationService, - MembershipService by roomMembersService, - RoomPushRuleService by roomPushRuleService, - RoomAccountDataService by roomAccountDataService, - RoomVersionService by roomVersionService { +internal class DefaultRoom( + override val roomId: String, + private val roomSummaryDataSource: RoomSummaryDataSource, + private val roomCryptoService: RoomCryptoService, + private val timelineService: TimelineService, + private val threadsService: ThreadsService, + private val threadsLocalService: ThreadsLocalService, + private val sendService: SendService, + private val draftService: DraftService, + private val stateService: StateService, + private val uploadsService: UploadsService, + private val reportingService: ReportingService, + private val roomCallService: RoomCallService, + private val readService: ReadService, + private val typingService: TypingService, + private val aliasService: AliasService, + private val tagsService: TagsService, + private val relationService: RelationService, + private val roomMembersService: MembershipService, + private val roomPushRuleService: RoomPushRuleService, + private val roomAccountDataService: RoomAccountDataService, + private val roomVersionService: RoomVersionService, + private val viaParameterFinder: ViaParameterFinder, + override val coroutineDispatchers: MatrixCoroutineDispatchers +) : Room { override fun getRoomSummaryLive(): LiveData> { return roomSummaryDataSource.getRoomSummaryLive(roomId) @@ -107,69 +80,28 @@ internal class DefaultRoom(override val roomId: String, return roomSummaryDataSource.getRoomSummary(roomId) } - override fun isEncrypted(): Boolean { - return cryptoService.isRoomEncrypted(roomId) - } - - override fun encryptionAlgorithm(): String? { - return cryptoService.getEncryptionAlgorithm(roomId) - } - - override fun shouldEncryptForInvitedMembers(): Boolean { - return cryptoService.shouldEncryptForInvitedMembers(roomId) - } - - override suspend fun prepareToEncrypt() { - awaitCallback { - cryptoService.prepareToEncrypt(roomId, it) - } - } - - override suspend fun enableEncryption(algorithm: String, force: Boolean) { - when { - (!force && isEncrypted() && encryptionAlgorithm() == MXCRYPTO_ALGORITHM_MEGOLM) -> { - throw IllegalStateException("Encryption is already enabled for this room") - } - (!force && algorithm != MXCRYPTO_ALGORITHM_MEGOLM) -> { - throw InvalidParameterException("Only MXCRYPTO_ALGORITHM_MEGOLM algorithm is supported") - } - else -> { - val params = SendStateTask.Params( - roomId = roomId, - stateKey = "", - eventType = EventType.STATE_ROOM_ENCRYPTION, - body = mapOf( - "algorithm" to algorithm - )) - - sendStateTask.execute(params) - } - } - } - - override suspend fun search(searchTerm: String, - nextBatch: String?, - orderByRecent: Boolean, - limit: Int, - beforeLimit: Int, - afterLimit: Int, - includeProfile: Boolean): SearchResult { - return searchTask.execute( - SearchTask.Params( - searchTerm = searchTerm, - roomId = roomId, - nextBatch = nextBatch, - orderByRecent = orderByRecent, - limit = limit, - beforeLimit = beforeLimit, - afterLimit = afterLimit, - includeProfile = includeProfile - ) - ) - } - override fun asSpace(): Space? { if (roomSummary()?.roomType != RoomType.SPACE) return null return DefaultSpace(this, roomSummaryDataSource, viaParameterFinder) } + + override fun timelineService() = timelineService + override fun threadsService() = threadsService + override fun threadsLocalService() = threadsLocalService + override fun sendService() = sendService + override fun draftService() = draftService + override fun stateService() = stateService + override fun uploadsService() = uploadsService + override fun reportingService() = reportingService + override fun roomCallService() = roomCallService + override fun readService() = readService + override fun typingService() = typingService + override fun aliasService() = aliasService + override fun tagsService() = tagsService + override fun relationService() = relationService + override fun roomCryptoService() = roomCryptoService + override fun membershipService() = roomMembersService + override fun roomPushRuleService() = roomPushRuleService + override fun roomAccountDataService() = roomAccountDataService + override fun roomVersionService() = roomVersionService } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt index 15ce5810c8..a8158d9bef 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt @@ -28,14 +28,16 @@ import org.matrix.android.sdk.api.session.events.model.content.EncryptedEventCon import org.matrix.android.sdk.api.session.events.model.getRelationContent import org.matrix.android.sdk.api.session.events.model.toContent import org.matrix.android.sdk.api.session.events.model.toModel +import org.matrix.android.sdk.api.session.room.getTimelineEvent import org.matrix.android.sdk.api.session.room.model.PollSummaryContent import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent import org.matrix.android.sdk.api.session.room.model.ReferencesAggregatedContent import org.matrix.android.sdk.api.session.room.model.VoteInfo import org.matrix.android.sdk.api.session.room.model.VoteSummary +import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconInfoContent +import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconLocationDataContent import org.matrix.android.sdk.api.session.room.model.message.MessageContent import org.matrix.android.sdk.api.session.room.model.message.MessageEndPollContent -import org.matrix.android.sdk.api.session.room.model.message.MessageLiveLocationContent import org.matrix.android.sdk.api.session.room.model.message.MessagePollContent import org.matrix.android.sdk.api.session.room.model.message.MessagePollResponseContent import org.matrix.android.sdk.api.session.room.model.message.MessageRelationContent @@ -91,7 +93,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor( // EventType.KEY_VERIFICATION_READY, EventType.KEY_VERIFICATION_KEY, EventType.ENCRYPTED - ) + EventType.POLL_START + EventType.POLL_RESPONSE + EventType.POLL_END + EventType.BEACON_LOCATION_DATA + ) + EventType.POLL_START + EventType.POLL_RESPONSE + EventType.POLL_END + EventType.STATE_ROOM_BEACON_INFO + EventType.BEACON_LOCATION_DATA override fun shouldProcess(eventId: String, eventType: String, insertType: EventInsertType): Boolean { return allowedTypes.contains(eventType) @@ -106,12 +108,12 @@ internal class EventRelationsAggregationProcessor @Inject constructor( } val isLocalEcho = LocalEcho.isLocalEchoId(event.eventId ?: "") when (event.type) { - EventType.REACTION -> { + EventType.REACTION -> { // we got a reaction!! Timber.v("###REACTION in room $roomId , reaction eventID ${event.eventId}") handleReaction(realm, event, roomId, isLocalEcho) } - EventType.MESSAGE -> { + EventType.MESSAGE -> { if (event.unsignedData?.relations?.annotations != null) { Timber.v("###REACTION Aggregation in room $roomId for event ${event.eventId}") handleInitialAggregatedRelations(realm, event, roomId, event.unsignedData.relations.annotations) @@ -137,7 +139,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor( EventType.KEY_VERIFICATION_START, EventType.KEY_VERIFICATION_MAC, EventType.KEY_VERIFICATION_READY, - EventType.KEY_VERIFICATION_KEY -> { + EventType.KEY_VERIFICATION_KEY -> { Timber.v("## SAS REF in room $roomId for event ${event.eventId}") event.content.toModel()?.relatesTo?.let { if (it.type == RelationType.REFERENCE && it.eventId != null) { @@ -146,7 +148,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor( } } - EventType.ENCRYPTED -> { + EventType.ENCRYPTED -> { // Relation type is in clear val encryptedEventContent = event.content.toModel() if (encryptedEventContent?.relatesTo?.type == RelationType.REPLACE || @@ -189,8 +191,8 @@ internal class EventRelationsAggregationProcessor @Inject constructor( } } in EventType.BEACON_LOCATION_DATA -> { - event.content.toModel(catchError = true)?.let { - liveLocationAggregationProcessor.handleLiveLocation(realm, event, it, roomId, isLocalEcho) + event.getClearContent().toModel(catchError = true)?.let { + liveLocationAggregationProcessor.handleBeaconLocationData(realm, event, it, roomId, isLocalEcho) } } } @@ -213,7 +215,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor( // } // } } - EventType.REDACTION -> { + EventType.REDACTION -> { val eventToPrune = event.redacts?.let { EventEntity.where(realm, eventId = it).findFirst() } ?: return when (eventToPrune.type) { @@ -233,7 +235,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor( } } } - in EventType.POLL_START -> { + in EventType.POLL_START -> { val content: MessagePollContent? = event.content.toModel() if (content?.relatesTo?.type == RelationType.REPLACE) { Timber.v("###REPLACE in room $roomId for event ${event.eventId}") @@ -241,22 +243,22 @@ internal class EventRelationsAggregationProcessor @Inject constructor( handleReplace(realm, event, content, roomId, isLocalEcho) } } - in EventType.POLL_RESPONSE -> { + in EventType.POLL_RESPONSE -> { event.content.toModel(catchError = true)?.let { handleResponse(realm, event, it, roomId, isLocalEcho) } } - in EventType.POLL_END -> { + in EventType.POLL_END -> { event.content.toModel(catchError = true)?.let { handleEndPoll(realm, event, it, roomId, isLocalEcho) } } - in EventType.BEACON_LOCATION_DATA -> { - event.content.toModel(catchError = true)?.let { - liveLocationAggregationProcessor.handleLiveLocation(realm, event, it, roomId, isLocalEcho) + in EventType.STATE_ROOM_BEACON_INFO -> { + event.content.toModel(catchError = true)?.let { + liveLocationAggregationProcessor.handleBeaconInfo(realm, event, it, roomId, isLocalEcho) } } - else -> Timber.v("UnHandled event ${event.eventId}") + else -> Timber.v("UnHandled event ${event.eventId}") } } catch (t: Throwable) { Timber.e(t, "## Should not happen ") @@ -325,7 +327,8 @@ internal class EventRelationsAggregationProcessor @Inject constructor( totalVotes = 0, winnerVoteCount = 0, ) - .toContent()) + .toContent() + ) } val txId = event.unsignedData?.transactionId @@ -542,7 +545,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor( private fun getPollEvent(roomId: String, eventId: String): TimelineEvent? { val session = sessionManager.getSessionComponent(sessionId)?.session() - return session?.getRoom(roomId)?.getTimelineEvent(eventId) ?: return null.also { + return session?.roomService()?.getRoom(roomId)?.getTimelineEvent(eventId) ?: return null.also { Timber.v("## POLL target poll event $eventId not found in room $roomId") } } @@ -729,11 +732,13 @@ internal class EventRelationsAggregationProcessor @Inject constructor( EventType.KEY_VERIFICATION_READY, EventType.KEY_VERIFICATION_KEY, EventType.KEY_VERIFICATION_MAC -> currentState.toState(VerificationState.WAITING) - EventType.KEY_VERIFICATION_CANCEL -> currentState.toState(if (event.senderId == userId) { - VerificationState.CANCELED_BY_ME - } else { - VerificationState.CANCELED_BY_OTHER - }) + EventType.KEY_VERIFICATION_CANCEL -> currentState.toState( + if (event.senderId == userId) { + VerificationState.CANCELED_BY_ME + } else { + VerificationState.CANCELED_BY_OTHER + } + ) EventType.KEY_VERIFICATION_DONE -> currentState.toState(VerificationState.DONE) else -> VerificationState.REQUEST } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt index 10f75473b7..65ef94999f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt @@ -194,7 +194,8 @@ internal interface RoomAPI { @PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/state/{state_event_type}") suspend fun sendStateEvent(@Path("roomId") roomId: String, @Path("state_event_type") stateEventType: String, - @Body params: JsonDict) + @Body params: JsonDict + ): SendResponse /** * Send a generic state event @@ -208,7 +209,8 @@ internal interface RoomAPI { suspend fun sendStateEvent(@Path("roomId") roomId: String, @Path("state_event_type") stateEventType: String, @Path("state_key") stateKey: String, - @Body params: JsonDict) + @Body params: JsonDict + ): SendResponse /** * Get state events of a room diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomFactory.kt index 72a3f9ab22..01c4fd1501 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomFactory.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomFactory.kt @@ -17,13 +17,13 @@ package org.matrix.android.sdk.internal.session.room import org.matrix.android.sdk.api.MatrixCoroutineDispatchers -import org.matrix.android.sdk.api.session.crypto.CryptoService import org.matrix.android.sdk.api.session.room.Room import org.matrix.android.sdk.internal.session.SessionScope import org.matrix.android.sdk.internal.session.permalinks.ViaParameterFinder import org.matrix.android.sdk.internal.session.room.accountdata.DefaultRoomAccountDataService import org.matrix.android.sdk.internal.session.room.alias.DefaultAliasService import org.matrix.android.sdk.internal.session.room.call.DefaultRoomCallService +import org.matrix.android.sdk.internal.session.room.crypto.DefaultRoomCryptoService import org.matrix.android.sdk.internal.session.room.draft.DefaultDraftService import org.matrix.android.sdk.internal.session.room.membership.DefaultMembershipService import org.matrix.android.sdk.internal.session.room.notification.DefaultRoomPushRuleService @@ -32,7 +32,6 @@ import org.matrix.android.sdk.internal.session.room.relation.DefaultRelationServ import org.matrix.android.sdk.internal.session.room.reporting.DefaultReportingService import org.matrix.android.sdk.internal.session.room.send.DefaultSendService import org.matrix.android.sdk.internal.session.room.state.DefaultStateService -import org.matrix.android.sdk.internal.session.room.state.SendStateTask import org.matrix.android.sdk.internal.session.room.summary.RoomSummaryDataSource import org.matrix.android.sdk.internal.session.room.tags.DefaultTagsService import org.matrix.android.sdk.internal.session.room.threads.DefaultThreadsService @@ -41,7 +40,6 @@ import org.matrix.android.sdk.internal.session.room.timeline.DefaultTimelineServ import org.matrix.android.sdk.internal.session.room.typing.DefaultTypingService import org.matrix.android.sdk.internal.session.room.uploads.DefaultUploadsService import org.matrix.android.sdk.internal.session.room.version.DefaultRoomVersionService -import org.matrix.android.sdk.internal.session.search.SearchTask import javax.inject.Inject internal interface RoomFactory { @@ -49,36 +47,36 @@ internal interface RoomFactory { } @SessionScope -internal class DefaultRoomFactory @Inject constructor(private val cryptoService: CryptoService, - private val roomSummaryDataSource: RoomSummaryDataSource, - private val timelineServiceFactory: DefaultTimelineService.Factory, - private val threadsServiceFactory: DefaultThreadsService.Factory, - private val threadsLocalServiceFactory: DefaultThreadsLocalService.Factory, - private val sendServiceFactory: DefaultSendService.Factory, - private val draftServiceFactory: DefaultDraftService.Factory, - private val stateServiceFactory: DefaultStateService.Factory, - private val uploadsServiceFactory: DefaultUploadsService.Factory, - private val reportingServiceFactory: DefaultReportingService.Factory, - private val roomCallServiceFactory: DefaultRoomCallService.Factory, - private val readServiceFactory: DefaultReadService.Factory, - private val typingServiceFactory: DefaultTypingService.Factory, - private val aliasServiceFactory: DefaultAliasService.Factory, - private val tagsServiceFactory: DefaultTagsService.Factory, - private val relationServiceFactory: DefaultRelationService.Factory, - private val membershipServiceFactory: DefaultMembershipService.Factory, - private val roomPushRuleServiceFactory: DefaultRoomPushRuleService.Factory, - private val roomVersionServiceFactory: DefaultRoomVersionService.Factory, - private val roomAccountDataServiceFactory: DefaultRoomAccountDataService.Factory, - private val sendStateTask: SendStateTask, - private val viaParameterFinder: ViaParameterFinder, - private val searchTask: SearchTask, - private val coroutineDispatchers: MatrixCoroutineDispatchers) : - RoomFactory { +internal class DefaultRoomFactory @Inject constructor( + private val roomSummaryDataSource: RoomSummaryDataSource, + private val timelineServiceFactory: DefaultTimelineService.Factory, + private val threadsServiceFactory: DefaultThreadsService.Factory, + private val threadsLocalServiceFactory: DefaultThreadsLocalService.Factory, + private val sendServiceFactory: DefaultSendService.Factory, + private val draftServiceFactory: DefaultDraftService.Factory, + private val stateServiceFactory: DefaultStateService.Factory, + private val uploadsServiceFactory: DefaultUploadsService.Factory, + private val reportingServiceFactory: DefaultReportingService.Factory, + private val roomCallServiceFactory: DefaultRoomCallService.Factory, + private val readServiceFactory: DefaultReadService.Factory, + private val typingServiceFactory: DefaultTypingService.Factory, + private val aliasServiceFactory: DefaultAliasService.Factory, + private val tagsServiceFactory: DefaultTagsService.Factory, + private val relationServiceFactory: DefaultRelationService.Factory, + private val roomCryptoServiceFactory: DefaultRoomCryptoService.Factory, + private val membershipServiceFactory: DefaultMembershipService.Factory, + private val roomPushRuleServiceFactory: DefaultRoomPushRuleService.Factory, + private val roomVersionServiceFactory: DefaultRoomVersionService.Factory, + private val roomAccountDataServiceFactory: DefaultRoomAccountDataService.Factory, + private val viaParameterFinder: ViaParameterFinder, + private val coroutineDispatchers: MatrixCoroutineDispatchers +) : RoomFactory { override fun create(roomId: String): Room { return DefaultRoom( roomId = roomId, roomSummaryDataSource = roomSummaryDataSource, + roomCryptoService = roomCryptoServiceFactory.create(roomId), timelineService = timelineServiceFactory.create(roomId), threadsService = threadsServiceFactory.create(roomId), threadsLocalService = threadsLocalServiceFactory.create(roomId), @@ -92,14 +90,11 @@ internal class DefaultRoomFactory @Inject constructor(private val cryptoService: typingService = typingServiceFactory.create(roomId), aliasService = aliasServiceFactory.create(roomId), tagsService = tagsServiceFactory.create(roomId), - cryptoService = cryptoService, relationService = relationServiceFactory.create(roomId), roomMembersService = membershipServiceFactory.create(roomId), roomPushRuleService = roomPushRuleServiceFactory.create(roomId), roomAccountDataService = roomAccountDataServiceFactory.create(roomId), roomVersionService = roomVersionServiceFactory.create(roomId), - sendStateTask = sendStateTask, - searchTask = searchTask, viaParameterFinder = viaParameterFinder, coroutineDispatchers = coroutineDispatchers ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/aggregation/livelocation/DefaultLiveLocationAggregationProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/aggregation/livelocation/DefaultLiveLocationAggregationProcessor.kt index 95e196c762..997e31a109 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/aggregation/livelocation/DefaultLiveLocationAggregationProcessor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/aggregation/livelocation/DefaultLiveLocationAggregationProcessor.kt @@ -17,69 +17,78 @@ package org.matrix.android.sdk.internal.session.room.aggregation.livelocation import io.realm.Realm -import org.matrix.android.sdk.api.extensions.orFalse +import org.matrix.android.sdk.api.extensions.orTrue import org.matrix.android.sdk.api.session.events.model.Event -import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.toContent import org.matrix.android.sdk.api.session.events.model.toModel -import org.matrix.android.sdk.api.session.room.model.livelocation.LiveLocationBeaconContent -import org.matrix.android.sdk.api.session.room.model.message.MessageLiveLocationContent +import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconInfoContent +import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconLocationDataContent import org.matrix.android.sdk.internal.database.mapper.ContentMapper -import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntity -import org.matrix.android.sdk.internal.database.query.getOrNull +import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntity +import org.matrix.android.sdk.internal.database.query.getOrCreate import timber.log.Timber import javax.inject.Inject internal class DefaultLiveLocationAggregationProcessor @Inject constructor() : LiveLocationAggregationProcessor { - override fun handleLiveLocation(realm: Realm, event: Event, content: MessageLiveLocationContent, roomId: String, isLocalEcho: Boolean) { - val locationSenderId = event.senderId ?: return - - // We shouldn't process local echos - if (isLocalEcho) { + override fun handleBeaconInfo(realm: Realm, event: Event, content: MessageBeaconInfoContent, roomId: String, isLocalEcho: Boolean) { + if (event.senderId.isNullOrEmpty() || isLocalEcho) { return } - // A beacon info state event has to be sent before sending location - // TODO handle missing check of m_relatesTo field - var beaconInfoEntity: CurrentStateEventEntity? = null - val eventTypesIterator = EventType.STATE_ROOM_BEACON_INFO.iterator() - while (beaconInfoEntity == null && eventTypesIterator.hasNext()) { - beaconInfoEntity = CurrentStateEventEntity.getOrNull(realm, roomId, locationSenderId, eventTypesIterator.next()) - } - - if (beaconInfoEntity == null) { - Timber.v("## LIVE LOCATION. There is not any beacon info which should be emitted before sending location updates") - return - } - val beaconInfoContent = ContentMapper.map(beaconInfoEntity.root?.content)?.toModel(catchError = true) - if (beaconInfoContent == null) { - Timber.v("## LIVE LOCATION. Beacon info content is invalid") - return - } - - // Check if live location is ended - if (!beaconInfoContent.getBestBeaconInfo()?.isLive.orFalse()) { - Timber.v("## LIVE LOCATION. Beacon info is not live anymore") - return - } - - // Check if beacon info is outdated - if (isBeaconInfoOutdated(beaconInfoContent, content)) { - Timber.v("## LIVE LOCATION. Beacon info has timeout") - beaconInfoContent.hasTimedOut = true + val targetEventId = if (content.isLive.orTrue()) { + event.eventId } else { - beaconInfoContent.lastLocationContent = content + // when live is set to false, we use the id of the event that should have been replaced + event.unsignedData?.replacesState } - beaconInfoEntity.root?.content = ContentMapper.map(beaconInfoContent.toContent()) + if (targetEventId.isNullOrEmpty()) { + Timber.w("no target event id found for the beacon content") + return + } + + val aggregatedSummary = LiveLocationShareAggregatedSummaryEntity.getOrCreate( + realm = realm, + roomId = roomId, + eventId = targetEventId + ) + + Timber.d("updating summary of id=$targetEventId with isLive=${content.isLive}") + + aggregatedSummary.endOfLiveTimestampMillis = content.getBestTimestampMillis()?.let { it + (content.timeout ?: 0) } + aggregatedSummary.isActive = content.isLive } - private fun isBeaconInfoOutdated(beaconInfoContent: LiveLocationBeaconContent, - liveLocationContent: MessageLiveLocationContent): Boolean { - val beaconInfoStartTime = beaconInfoContent.getBestTimestampAsMilliseconds() ?: 0 - val liveLocationEventTime = liveLocationContent.getBestTimestampAsMilliseconds() ?: 0 - val timeout = beaconInfoContent.getBestBeaconInfo()?.timeout ?: 0 - return liveLocationEventTime - beaconInfoStartTime > timeout + override fun handleBeaconLocationData(realm: Realm, event: Event, content: MessageBeaconLocationDataContent, roomId: String, isLocalEcho: Boolean) { + if (event.senderId.isNullOrEmpty() || isLocalEcho) { + return + } + + val targetEventId = content.relatesTo?.eventId + + if (targetEventId.isNullOrEmpty()) { + Timber.w("no target event id found for the live location content") + return + } + + val aggregatedSummary = LiveLocationShareAggregatedSummaryEntity.getOrCreate( + realm = realm, + roomId = roomId, + eventId = targetEventId + ) + val updatedLocationTimestamp = content.getBestTimestampMillis() ?: 0 + val currentLocationTimestamp = ContentMapper + .map(aggregatedSummary.lastLocationContent) + .toModel() + ?.getBestTimestampMillis() + ?: 0 + + if (updatedLocationTimestamp.isMoreRecentThan(currentLocationTimestamp)) { + Timber.d("updating last location of the summary of id=$targetEventId") + aggregatedSummary.lastLocationContent = ContentMapper.map(content.toContent()) + } } + + private fun Long.isMoreRecentThan(timestamp: Long) = this > timestamp } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/aggregation/livelocation/LiveLocationAggregationProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/aggregation/livelocation/LiveLocationAggregationProcessor.kt index 7b5f23e243..c0be96f83d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/aggregation/livelocation/LiveLocationAggregationProcessor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/aggregation/livelocation/LiveLocationAggregationProcessor.kt @@ -18,12 +18,23 @@ package org.matrix.android.sdk.internal.session.room.aggregation.livelocation import io.realm.Realm import org.matrix.android.sdk.api.session.events.model.Event -import org.matrix.android.sdk.api.session.room.model.message.MessageLiveLocationContent +import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconInfoContent +import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconLocationDataContent internal interface LiveLocationAggregationProcessor { - fun handleLiveLocation(realm: Realm, - event: Event, - content: MessageLiveLocationContent, - roomId: String, - isLocalEcho: Boolean) + fun handleBeaconInfo( + realm: Realm, + event: Event, + content: MessageBeaconInfoContent, + roomId: String, + isLocalEcho: Boolean, + ) + + fun handleBeaconLocationData( + realm: Realm, + event: Event, + content: MessageBeaconLocationDataContent, + roomId: String, + isLocalEcho: Boolean, + ) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/crypto/DefaultRoomCryptoService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/crypto/DefaultRoomCryptoService.kt new file mode 100644 index 0000000000..2546c58cc7 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/crypto/DefaultRoomCryptoService.kt @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.session.room.crypto + +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM +import org.matrix.android.sdk.api.session.crypto.CryptoService +import org.matrix.android.sdk.api.session.events.model.EventType +import org.matrix.android.sdk.api.session.room.crypto.RoomCryptoService +import org.matrix.android.sdk.api.util.awaitCallback +import org.matrix.android.sdk.internal.session.room.state.SendStateTask +import java.security.InvalidParameterException + +internal class DefaultRoomCryptoService @AssistedInject constructor( + @Assisted private val roomId: String, + private val cryptoService: CryptoService, + private val sendStateTask: SendStateTask, +) : RoomCryptoService { + + @AssistedFactory + interface Factory { + fun create(roomId: String): DefaultRoomCryptoService + } + + override fun isEncrypted(): Boolean { + return cryptoService.isRoomEncrypted(roomId) + } + + override fun encryptionAlgorithm(): String? { + return cryptoService.getEncryptionAlgorithm(roomId) + } + + override fun shouldEncryptForInvitedMembers(): Boolean { + return cryptoService.shouldEncryptForInvitedMembers(roomId) + } + + override suspend fun prepareToEncrypt() { + awaitCallback { + cryptoService.prepareToEncrypt(roomId, it) + } + } + + override suspend fun enableEncryption(algorithm: String, force: Boolean) { + when { + (!force && isEncrypted() && encryptionAlgorithm() == MXCRYPTO_ALGORITHM_MEGOLM) -> { + throw IllegalStateException("Encryption is already enabled for this room") + } + (!force && algorithm != MXCRYPTO_ALGORITHM_MEGOLM) -> { + throw InvalidParameterException("Only MXCRYPTO_ALGORITHM_MEGOLM algorithm is supported") + } + else -> { + val params = SendStateTask.Params( + roomId = roomId, + stateKey = "", + eventType = EventType.STATE_ROOM_ENCRYPTION, + body = mapOf( + "algorithm" to algorithm + ) + ) + + sendStateTask.execute(params) + } + } + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/notification/DefaultRoomPushRuleService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/notification/DefaultRoomPushRuleService.kt index 7af54a45ca..85f53e1346 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/notification/DefaultRoomPushRuleService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/notification/DefaultRoomPushRuleService.kt @@ -22,7 +22,7 @@ import com.zhuinden.monarchy.Monarchy import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject -import org.matrix.android.sdk.api.pushrules.RuleScope +import org.matrix.android.sdk.api.session.pushrules.RuleScope import org.matrix.android.sdk.api.session.room.notification.RoomNotificationState import org.matrix.android.sdk.api.session.room.notification.RoomPushRuleService import org.matrix.android.sdk.internal.database.model.PushRuleEntity diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/notification/RoomPushRule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/notification/RoomPushRule.kt index d2c0d13b51..2c74e2a1e5 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/notification/RoomPushRule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/notification/RoomPushRule.kt @@ -16,8 +16,8 @@ package org.matrix.android.sdk.internal.session.room.notification -import org.matrix.android.sdk.api.pushrules.RuleKind -import org.matrix.android.sdk.api.pushrules.rest.PushRule +import org.matrix.android.sdk.api.session.pushrules.RuleKind +import org.matrix.android.sdk.api.session.pushrules.rest.PushRule internal data class RoomPushRule( val kind: RuleKind, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/notification/RoomPushRuleMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/notification/RoomPushRuleMapper.kt index 86d2e6c619..a5a5ab58ba 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/notification/RoomPushRuleMapper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/notification/RoomPushRuleMapper.kt @@ -16,13 +16,13 @@ package org.matrix.android.sdk.internal.session.room.notification -import org.matrix.android.sdk.api.pushrules.Action -import org.matrix.android.sdk.api.pushrules.Kind -import org.matrix.android.sdk.api.pushrules.RuleSetKey -import org.matrix.android.sdk.api.pushrules.getActions -import org.matrix.android.sdk.api.pushrules.rest.PushCondition -import org.matrix.android.sdk.api.pushrules.rest.PushRule -import org.matrix.android.sdk.api.pushrules.toJson +import org.matrix.android.sdk.api.session.pushrules.Action +import org.matrix.android.sdk.api.session.pushrules.Kind +import org.matrix.android.sdk.api.session.pushrules.RuleSetKey +import org.matrix.android.sdk.api.session.pushrules.getActions +import org.matrix.android.sdk.api.session.pushrules.rest.PushCondition +import org.matrix.android.sdk.api.session.pushrules.rest.PushRule +import org.matrix.android.sdk.api.session.pushrules.toJson import org.matrix.android.sdk.api.session.room.notification.RoomNotificationState import org.matrix.android.sdk.internal.database.mapper.PushRulesMapper import org.matrix.android.sdk.internal.database.model.PushRuleEntity diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/notification/SetRoomNotificationStateTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/notification/SetRoomNotificationStateTask.kt index d31f8a9d85..021d7dbefb 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/notification/SetRoomNotificationStateTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/notification/SetRoomNotificationStateTask.kt @@ -18,7 +18,7 @@ package org.matrix.android.sdk.internal.session.room.notification import com.zhuinden.monarchy.Monarchy import io.realm.Realm -import org.matrix.android.sdk.api.pushrules.RuleScope +import org.matrix.android.sdk.api.session.pushrules.RuleScope import org.matrix.android.sdk.api.session.room.notification.RoomNotificationState import org.matrix.android.sdk.internal.database.model.PushRuleEntity import org.matrix.android.sdk.internal.database.query.where diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoEventFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoEventFactory.kt index bb16563f96..0d75a375cc 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoEventFactory.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoEventFactory.kt @@ -37,13 +37,13 @@ import org.matrix.android.sdk.api.session.room.model.message.LocationAsset import org.matrix.android.sdk.api.session.room.model.message.LocationAssetType import org.matrix.android.sdk.api.session.room.model.message.LocationInfo import org.matrix.android.sdk.api.session.room.model.message.MessageAudioContent +import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconLocationDataContent import org.matrix.android.sdk.api.session.room.model.message.MessageContent import org.matrix.android.sdk.api.session.room.model.message.MessageContentWithFormattedBody import org.matrix.android.sdk.api.session.room.model.message.MessageEndPollContent import org.matrix.android.sdk.api.session.room.model.message.MessageFileContent import org.matrix.android.sdk.api.session.room.model.message.MessageFormat import org.matrix.android.sdk.api.session.room.model.message.MessageImageContent -import org.matrix.android.sdk.api.session.room.model.message.MessageLiveLocationContent import org.matrix.android.sdk.api.session.room.model.message.MessageLocationContent import org.matrix.android.sdk.api.session.room.model.message.MessagePollContent import org.matrix.android.sdk.api.session.room.model.message.MessagePollResponseContent @@ -71,7 +71,6 @@ import org.matrix.android.sdk.internal.session.content.ThumbnailExtractor import org.matrix.android.sdk.internal.session.permalinks.PermalinkFactory import org.matrix.android.sdk.internal.session.room.send.pills.TextPillsUtils import java.util.UUID -import java.util.concurrent.TimeUnit import javax.inject.Inject /** @@ -124,7 +123,8 @@ internal class LocalEchoEventFactory @Inject constructor( newBodyAutoMarkdown: Boolean, msgType: String, compatibilityText: String): Event { - return createMessageEvent(roomId, + return createMessageEvent( + roomId, MessageTextContent( msgType = msgType, body = compatibilityText, @@ -132,7 +132,8 @@ internal class LocalEchoEventFactory @Inject constructor( newContent = createTextContent(newBodyText, newBodyAutoMarkdown) .toMessageTextContent(msgType) .toContent() - )) + ) + ) } private fun createPollContent(question: String, @@ -188,7 +189,8 @@ internal class LocalEchoEventFactory @Inject constructor( eventId = localId, type = EventType.POLL_RESPONSE.first(), content = content.toContent(), - unsignedData = UnsignedData(age = null, transactionId = localId)) + unsignedData = UnsignedData(age = null, transactionId = localId) + ) } fun createPollEvent(roomId: String, @@ -204,7 +206,8 @@ internal class LocalEchoEventFactory @Inject constructor( eventId = localId, type = EventType.POLL_START.first(), content = content.toContent(), - unsignedData = UnsignedData(age = null, transactionId = localId)) + unsignedData = UnsignedData(age = null, transactionId = localId) + ) } fun createEndPollEvent(roomId: String, @@ -223,7 +226,8 @@ internal class LocalEchoEventFactory @Inject constructor( eventId = localId, type = EventType.POLL_END.first(), content = content.toContent(), - unsignedData = UnsignedData(age = null, transactionId = localId)) + unsignedData = UnsignedData(age = null, transactionId = localId) + ) } fun createLocationEvent(roomId: String, @@ -238,7 +242,7 @@ internal class LocalEchoEventFactory @Inject constructor( body = geoUri, unstableLocationInfo = LocationInfo(geoUri = geoUri, description = geoUri), unstableLocationAsset = LocationAsset(type = assetType), - unstableTs = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()), + unstableTimestampMillis = System.currentTimeMillis(), unstableText = geoUri ) return createMessageEvent(roomId, content) @@ -250,14 +254,14 @@ internal class LocalEchoEventFactory @Inject constructor( longitude: Double, uncertainty: Double?): Event { val geoUri = buildGeoUri(latitude, longitude, uncertainty) - val content = MessageLiveLocationContent( + val content = MessageBeaconLocationDataContent( body = geoUri, relatesTo = RelationDefaultContent( type = RelationType.REFERENCE, eventId = beaconInfoEventId ), unstableLocationInfo = LocationInfo(geoUri = geoUri, description = geoUri), - unstableTimestampAsMilliseconds = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()), + unstableTimestampMillis = System.currentTimeMillis(), ) val localId = LocalEcho.createLocalEchoId() return Event( @@ -267,7 +271,8 @@ internal class LocalEchoEventFactory @Inject constructor( eventId = localId, type = EventType.BEACON_LOCATION_DATA.first(), content = content.toContent(), - unsignedData = UnsignedData(age = null, transactionId = localId)) + unsignedData = UnsignedData(age = null, transactionId = localId) + ) } fun createReplaceTextOfReply(roomId: String, @@ -297,7 +302,8 @@ internal class LocalEchoEventFactory @Inject constructor( // val replyFallback = buildReplyFallback(body, originalEvent.root.senderId ?: "", newBodyText) - return createMessageEvent(roomId, + return createMessageEvent( + roomId, MessageTextContent( msgType = msgType, body = compatibilityText, @@ -309,7 +315,8 @@ internal class LocalEchoEventFactory @Inject constructor( formattedBody = replyFormatted ) .toContent() - )) + ) + ) } fun createMediaEvent(roomId: String, @@ -341,7 +348,8 @@ internal class LocalEchoEventFactory @Inject constructor( eventId = localId, type = EventType.REACTION, content = content.toContent(), - unsignedData = UnsignedData(age = null, transactionId = localId)) + unsignedData = UnsignedData(age = null, transactionId = localId) + ) } private fun createImageEvent(roomId: String, attachment: ContentAttachmentData, rootThreadEventId: String?): Event { @@ -532,8 +540,10 @@ internal class LocalEchoEventFactory @Inject constructor( content.toThreadTextContent( rootThreadEventId = rootThreadEventId, latestThreadEventId = localEchoRepository.getLatestThreadEvent(rootThreadEventId), - msgType = msgType) - .toContent()) + msgType = msgType + ) + .toContent() + ) } private fun dummyOriginServerTs(): Long { @@ -582,7 +592,9 @@ internal class LocalEchoEventFactory @Inject constructor( relatesTo = generateReplyRelationContent( eventId = eventId, rootThreadEventId = rootThreadEventId, - showInThread = showInThread)) + showInThread = showInThread + ) + ) return createMessageEvent(roomId, content) } @@ -605,7 +617,8 @@ internal class LocalEchoEventFactory @Inject constructor( eventId = it, isFallingBack = showInThread, // False when is a rich reply from within a thread, and true when is a reply that should be visible from threads - inReplyTo = ReplyToContent(eventId = eventId)) + inReplyTo = ReplyToContent(eventId = eventId) + ) } ?: RelationDefaultContent(null, null, ReplyToContent(eventId = eventId)) private fun buildFormattedReply(permalink: String, userLink: String, userId: String, bodyFormatted: String, newBodyFormatted: String): String { @@ -740,13 +753,15 @@ internal class LocalEchoEventFactory @Inject constructor( .toThreadTextContent( rootThreadEventId = rootThreadEventId, latestThreadEventId = localEchoRepository.getLatestThreadEvent(rootThreadEventId), - msgType = MessageType.MSGTYPE_TEXT) + msgType = MessageType.MSGTYPE_TEXT + ) ) } else { createFormattedTextEvent( roomId, markdownParser.parse(quoteText, force = true, advanced = autoMarkdown), - MessageType.MSGTYPE_TEXT) + MessageType.MSGTYPE_TEXT + ) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/DefaultStateService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/DefaultStateService.kt index 89d33f98d2..e5c7a75cb6 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/DefaultStateService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/DefaultStateService.kt @@ -33,8 +33,7 @@ import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibility import org.matrix.android.sdk.api.session.room.model.RoomJoinRules import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesAllowEntry import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesContent -import org.matrix.android.sdk.api.session.room.model.livelocation.BeaconInfo -import org.matrix.android.sdk.api.session.room.model.livelocation.LiveLocationBeaconContent +import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconInfoContent import org.matrix.android.sdk.api.session.room.state.StateService import org.matrix.android.sdk.api.util.JsonDict import org.matrix.android.sdk.api.util.MimeTypes @@ -74,14 +73,14 @@ internal class DefaultStateService @AssistedInject constructor(@Assisted private eventType: String, stateKey: String, body: JsonDict - ) { + ): String { val params = SendStateTask.Params( roomId = roomId, stateKey = stateKey, eventType = eventType, body = body.toSafeJson(eventType) ) - sendStateTask.executeRetry(params, 3) + return sendStateTask.executeRetry(params, 3) } private fun JsonDict.toSafeJson(eventType: String): JsonDict { @@ -193,20 +192,13 @@ internal class DefaultStateService @AssistedInject constructor(@Assisted private override suspend fun stopLiveLocation(userId: String) { getLiveLocationBeaconInfo(userId, true)?.let { beaconInfoStateEvent -> - beaconInfoStateEvent.getClearContent()?.toModel()?.let { content -> - val beaconContent = LiveLocationBeaconContent( - unstableBeaconInfo = BeaconInfo( - description = content.getBestBeaconInfo()?.description, - timeout = content.getBestBeaconInfo()?.timeout, - isLive = false, - ), - unstableTimestampAsMilliseconds = System.currentTimeMillis() - ).toContent() + beaconInfoStateEvent.getClearContent()?.toModel()?.let { content -> + val updatedContent = content.copy(isLive = false).toContent() beaconInfoStateEvent.stateKey?.let { sendStateEvent( eventType = EventType.STATE_ROOM_BEACON_INFO.first(), - body = beaconContent, + body = updatedContent, stateKey = it ) } @@ -225,7 +217,7 @@ internal class DefaultStateService @AssistedInject constructor(@Assisted private } .firstOrNull { beaconInfoEvent -> !filterOnlyLive || - beaconInfoEvent.getClearContent()?.toModel()?.getBestBeaconInfo()?.isLive.orFalse() + beaconInfoEvent.getClearContent()?.toModel()?.isLive.orFalse() } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/SendStateTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/SendStateTask.kt index 56c69a05a6..59c9de2932 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/SendStateTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/SendStateTask.kt @@ -21,9 +21,10 @@ import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.room.RoomAPI import org.matrix.android.sdk.internal.task.Task +import timber.log.Timber import javax.inject.Inject -internal interface SendStateTask : Task { +internal interface SendStateTask : Task { data class Params( val roomId: String, val stateKey: String, @@ -37,9 +38,9 @@ internal class DefaultSendStateTask @Inject constructor( private val globalErrorReceiver: GlobalErrorReceiver ) : SendStateTask { - override suspend fun execute(params: SendStateTask.Params) { + override suspend fun execute(params: SendStateTask.Params): String { return executeRequest(globalErrorReceiver) { - if (params.stateKey.isEmpty()) { + val response = if (params.stateKey.isEmpty()) { roomAPI.sendStateEvent( roomId = params.roomId, stateEventType = params.eventType, @@ -53,6 +54,9 @@ internal class DefaultSendStateTask @Inject constructor( params = params.body ) } + response.eventId.also { + Timber.d("State event: $it just sent in room ${params.roomId}") + } } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryDataSource.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryDataSource.kt index 18a4f80547..96e8d3c73f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryDataSource.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryDataSource.kt @@ -26,7 +26,6 @@ import com.zhuinden.monarchy.Monarchy import io.realm.Realm import io.realm.RealmQuery import io.realm.kotlin.where -import org.matrix.android.sdk.api.MatrixCoroutineDispatchers import org.matrix.android.sdk.api.query.ActiveSpaceFilter import org.matrix.android.sdk.api.query.RoomCategoryFilter import org.matrix.android.sdk.api.query.isNormalized @@ -43,7 +42,6 @@ import org.matrix.android.sdk.api.session.room.summary.RoomAggregateNotification import org.matrix.android.sdk.api.session.space.SpaceSummaryQueryParams import org.matrix.android.sdk.api.util.Optional import org.matrix.android.sdk.api.util.toOptional -import org.matrix.android.sdk.internal.database.RealmSessionProvider import org.matrix.android.sdk.internal.database.mapper.RoomSummaryMapper import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields @@ -57,10 +55,8 @@ import javax.inject.Inject internal class RoomSummaryDataSource @Inject constructor( @SessionDatabase private val monarchy: Monarchy, - private val realmSessionProvider: RealmSessionProvider, private val roomSummaryMapper: RoomSummaryMapper, private val queryStringValueProcessor: QueryStringValueProcessor, - private val coroutineDispatchers: MatrixCoroutineDispatchers ) { fun getRoomSummary(roomIdOrAlias: String): RoomSummary? { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineEventDecryptor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineEventDecryptor.kt index 5c30dc20d9..de79661de0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineEventDecryptor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineEventDecryptor.kt @@ -99,9 +99,7 @@ internal class TimelineEventDecryptor @Inject constructor( executor?.execute { Realm.getInstance(realmConfiguration).use { realm -> try { - runBlocking { - processDecryptRequest(request, realm) - } + processDecryptRequest(request, realm) } catch (e: InterruptedException) { Timber.i("Decryption got interrupted") } @@ -121,7 +119,7 @@ internal class TimelineEventDecryptor @Inject constructor( } } - private suspend fun processDecryptRequest(request: DecryptionRequest, realm: Realm) { + private fun processDecryptRequest(request: DecryptionRequest, realm: Realm) { val event = request.event val timelineId = request.timelineId @@ -132,7 +130,8 @@ internal class TimelineEventDecryptor @Inject constructor( return } try { - val result = cryptoService.decryptEvent(request.event, timelineId) + // note: runBlocking should be used here while we are in realm single thread executor, to avoid thread switching + val result = runBlocking { cryptoService.decryptEvent(request.event, timelineId) } Timber.v("Successfully decrypted event ${event.eventId}") realm.executeTransaction { val eventId = event.eventId ?: return@executeTransaction diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/UIEchoManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/UIEchoManager.kt index bb92623249..f3218173d6 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/UIEchoManager.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/UIEchoManager.kt @@ -98,9 +98,7 @@ internal class UIEchoManager(private val listener: Listener) { val relatedEventID = timelineEvent.eventId val contents = inMemoryReactions[relatedEventID] ?: return timelineEvent - var existingAnnotationSummary = timelineEvent.annotations ?: EventAnnotationsSummary( - relatedEventID - ) + var existingAnnotationSummary = timelineEvent.annotations ?: EventAnnotationsSummary() val updateReactions = existingAnnotationSummary.reactionsSummary.toMutableList() contents.forEach { uiEchoReaction -> diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpace.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpace.kt index 303eda49d8..178a29a5a0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpace.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpace.kt @@ -60,7 +60,7 @@ internal class DefaultSpace( } ?: viaParameterFinder.computeViaParams(roomId, 3)) - room.sendStateEvent( + room.stateService().sendStateEvent( eventType = EventType.STATE_SPACE_CHILD, stateKey = roomId, body = SpaceChildContent( @@ -79,7 +79,7 @@ internal class DefaultSpace( // return // edit state event and set via to null - room.sendStateEvent( + room.stateService().sendStateEvent( eventType = EventType.STATE_SPACE_CHILD, stateKey = roomId, body = SpaceChildContent( @@ -91,19 +91,19 @@ internal class DefaultSpace( } override fun getChildInfo(roomId: String): SpaceChildContent? { - return room.getStateEvents(setOf(EventType.STATE_SPACE_CHILD), QueryStringValue.Equals(roomId)) + return room.stateService().getStateEvents(setOf(EventType.STATE_SPACE_CHILD), QueryStringValue.Equals(roomId)) .firstOrNull() ?.content.toModel() } override suspend fun setChildrenOrder(roomId: String, order: String?) { - val existing = room.getStateEvents(setOf(EventType.STATE_SPACE_CHILD), QueryStringValue.Equals(roomId)) + val existing = room.stateService().getStateEvents(setOf(EventType.STATE_SPACE_CHILD), QueryStringValue.Equals(roomId)) .firstOrNull() ?.content.toModel() ?: throw IllegalArgumentException("$roomId is not a child of this space") // edit state event and set via to null - room.sendStateEvent( + room.stateService().sendStateEvent( eventType = EventType.STATE_SPACE_CHILD, stateKey = roomId, body = SpaceChildContent( @@ -140,7 +140,7 @@ internal class DefaultSpace( // } override suspend fun setChildrenSuggested(roomId: String, suggested: Boolean) { - val existing = room.getStateEvents(setOf(EventType.STATE_SPACE_CHILD), QueryStringValue.Equals(roomId)) + val existing = room.stateService().getStateEvents(setOf(EventType.STATE_SPACE_CHILD), QueryStringValue.Equals(roomId)) .firstOrNull() ?.content.toModel() ?: throw IllegalArgumentException("$roomId is not a child of this space") @@ -150,7 +150,7 @@ internal class DefaultSpace( return } // edit state event and set via to null - room.sendStateEvent( + room.stateService().sendStateEvent( eventType = EventType.STATE_SPACE_CHILD, stateKey = roomId, body = SpaceChildContent( diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpaceService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpaceService.kt index 05cff7dd89..9320665688 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpaceService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpaceService.kt @@ -18,12 +18,15 @@ package org.matrix.android.sdk.internal.session.space import android.net.Uri import androidx.lifecycle.LiveData +import kotlinx.coroutines.withContext +import org.matrix.android.sdk.api.MatrixCoroutineDispatchers import org.matrix.android.sdk.api.query.QueryStringValue import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.toContent import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.room.RoomSortOrder +import org.matrix.android.sdk.api.session.room.getStateEvent import org.matrix.android.sdk.api.session.room.model.GuestAccess import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent @@ -64,7 +67,8 @@ internal class DefaultSpaceService @Inject constructor( private val stateEventDataSource: StateEventDataSource, private val peekSpaceTask: PeekSpaceTask, private val resolveSpaceInfoTask: ResolveSpaceInfoTask, - private val leaveRoomTask: LeaveRoomTask + private val leaveRoomTask: LeaveRoomTask, + private val coroutineDispatchers: MatrixCoroutineDispatchers, ) : SpaceService { override suspend fun createSpace(params: CreateSpaceParams): String { @@ -105,8 +109,10 @@ internal class DefaultSpaceService @Inject constructor( return roomSummaryDataSource.getSpaceSummaries(spaceSummaryQueryParams, sortOrder) } - override fun getRootSpaceSummaries(): List { - return roomSummaryDataSource.getRootSpaceSummaries() + override suspend fun getRootSpaceSummaries(): List { + return withContext(coroutineDispatchers.io) { + roomSummaryDataSource.getRootSpaceSummaries() + } } override suspend fun peekSpace(spaceId: String): SpacePeekResult { @@ -253,7 +259,7 @@ internal class DefaultSpaceService @Inject constructor( val room = roomGetter.getRoom(childRoomId) ?: throw IllegalArgumentException("Unknown Room $childRoomId") - room.sendStateEvent( + room.stateService().sendStateEvent( eventType = EventType.STATE_SPACE_PARENT, stateKey = parentSpaceId, body = SpaceParentContent( @@ -271,7 +277,7 @@ internal class DefaultSpaceService @Inject constructor( if (existingEvent != null) { // Should i check if it was sent by me? // we don't check power level, it will throw if you cannot do that - room.sendStateEvent( + room.stateService().sendStateEvent( eventType = EventType.STATE_SPACE_PARENT, stateKey = parentSpaceId, body = SpaceParentContent( diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponseHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponseHandler.kt index 97850e81d3..02a7a9a37f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponseHandler.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponseHandler.kt @@ -18,9 +18,9 @@ package org.matrix.android.sdk.internal.session.sync import androidx.work.ExistingPeriodicWorkPolicy import com.zhuinden.monarchy.Monarchy -import org.matrix.android.sdk.api.pushrules.PushRuleService -import org.matrix.android.sdk.api.pushrules.RuleScope import org.matrix.android.sdk.api.session.initsync.InitSyncStep +import org.matrix.android.sdk.api.session.pushrules.PushRuleService +import org.matrix.android.sdk.api.session.pushrules.RuleScope import org.matrix.android.sdk.api.session.sync.model.GroupsSyncResponse import org.matrix.android.sdk.api.session.sync.model.RoomsSyncResponse import org.matrix.android.sdk.api.session.sync.model.SyncResponse @@ -34,7 +34,7 @@ import org.matrix.android.sdk.internal.session.dispatchTo import org.matrix.android.sdk.internal.session.group.GetGroupDataWorker import org.matrix.android.sdk.internal.session.initsync.ProgressReporter import org.matrix.android.sdk.internal.session.initsync.reportSubtask -import org.matrix.android.sdk.internal.session.notification.ProcessEventForPushTask +import org.matrix.android.sdk.internal.session.pushrules.ProcessEventForPushTask import org.matrix.android.sdk.internal.session.sync.handler.CryptoSyncHandler import org.matrix.android.sdk.internal.session.sync.handler.GroupSyncHandler import org.matrix.android.sdk.internal.session.sync.handler.PresenceSyncHandler diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncTask.kt index bb0197a38d..197037f1cf 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncTask.kt @@ -107,7 +107,7 @@ internal class DefaultSyncTask @Inject constructor( val isInitialSync = token == null if (isInitialSync) { // We might want to get the user information in parallel too - val user = tryOrNull { session.getProfileAsUser(userId) } + val user = tryOrNull { session.profileService().getProfileAsUser(userId) } userStore.createOrUpdate( userId = userId, displayName = user?.displayName, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/UserAccountDataSyncHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/UserAccountDataSyncHandler.kt index fa9ba371f7..c213ea4bcf 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/UserAccountDataSyncHandler.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/UserAccountDataSyncHandler.kt @@ -22,13 +22,12 @@ import io.realm.RealmList import io.realm.kotlin.where import org.matrix.android.sdk.api.failure.GlobalError import org.matrix.android.sdk.api.failure.InitialSyncRequestReason -import org.matrix.android.sdk.api.pushrules.RuleScope -import org.matrix.android.sdk.api.pushrules.RuleSetKey -import org.matrix.android.sdk.api.pushrules.rest.GetPushRulesResponse import org.matrix.android.sdk.api.session.accountdata.UserAccountDataEvent import org.matrix.android.sdk.api.session.accountdata.UserAccountDataTypes import org.matrix.android.sdk.api.session.events.model.Content import org.matrix.android.sdk.api.session.events.model.toModel +import org.matrix.android.sdk.api.session.pushrules.RuleScope +import org.matrix.android.sdk.api.session.pushrules.RuleSetKey import org.matrix.android.sdk.api.session.room.model.RoomMemberContent import org.matrix.android.sdk.api.session.room.model.RoomSummary import org.matrix.android.sdk.api.session.sync.model.InvitedRoomSync @@ -55,6 +54,7 @@ import org.matrix.android.sdk.internal.di.SessionId import org.matrix.android.sdk.internal.di.UserId import org.matrix.android.sdk.internal.session.SessionListeners import org.matrix.android.sdk.internal.session.dispatchTo +import org.matrix.android.sdk.internal.session.pushers.GetPushRulesResponse import org.matrix.android.sdk.internal.session.room.RoomAvatarResolver import org.matrix.android.sdk.internal.session.room.membership.RoomDisplayNameResolver import org.matrix.android.sdk.internal.session.room.membership.RoomMemberHelper diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/RoomSyncHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/RoomSyncHandler.kt index afd8e1bb99..05dad983da 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/RoomSyncHandler.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/RoomSyncHandler.kt @@ -102,11 +102,11 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle data class LEFT(val data: Map) : HandlingStrategy() } - suspend fun handle(realm: Realm, - roomsSyncResponse: RoomsSyncResponse, - isInitialSync: Boolean, - aggregator: SyncResponsePostTreatmentAggregator, - reporter: ProgressReporter? = null) { + fun handle(realm: Realm, + roomsSyncResponse: RoomsSyncResponse, + isInitialSync: Boolean, + aggregator: SyncResponsePostTreatmentAggregator, + reporter: ProgressReporter? = null) { handleRoomSync(realm, HandlingStrategy.JOINED(roomsSyncResponse.join), isInitialSync, aggregator, reporter) handleRoomSync(realm, HandlingStrategy.INVITED(roomsSyncResponse.invite), isInitialSync, aggregator, reporter) handleRoomSync(realm, HandlingStrategy.LEFT(roomsSyncResponse.leave), isInitialSync, aggregator, reporter) @@ -120,11 +120,11 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle } // PRIVATE METHODS ***************************************************************************** - private suspend fun handleRoomSync(realm: Realm, - handlingStrategy: HandlingStrategy, - isInitialSync: Boolean, - aggregator: SyncResponsePostTreatmentAggregator, - reporter: ProgressReporter?) { + private fun handleRoomSync(realm: Realm, + handlingStrategy: HandlingStrategy, + isInitialSync: Boolean, + aggregator: SyncResponsePostTreatmentAggregator, + reporter: ProgressReporter?) { val insertType = if (isInitialSync) { EventInsertType.INITIAL_SYNC } else { @@ -157,11 +157,11 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle realm.insertOrUpdate(rooms) } - private suspend fun insertJoinRoomsFromInitSync(realm: Realm, - handlingStrategy: HandlingStrategy.JOINED, - syncLocalTimeStampMillis: Long, - aggregator: SyncResponsePostTreatmentAggregator, - reporter: ProgressReporter?) { + private fun insertJoinRoomsFromInitSync(realm: Realm, + handlingStrategy: HandlingStrategy.JOINED, + syncLocalTimeStampMillis: Long, + aggregator: SyncResponsePostTreatmentAggregator, + reporter: ProgressReporter?) { val bestChunkSize = computeBestChunkSize( listSize = handlingStrategy.data.keys.size, limit = (initialSyncStrategy as? InitialSyncStrategy.Optimized)?.maxRoomsToInsert ?: Int.MAX_VALUE @@ -199,12 +199,12 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle } } - private suspend fun handleJoinedRoom(realm: Realm, - roomId: String, - roomSync: RoomSync, - insertType: EventInsertType, - syncLocalTimestampMillis: Long, - aggregator: SyncResponsePostTreatmentAggregator): RoomEntity { + private fun handleJoinedRoom(realm: Realm, + roomId: String, + roomSync: RoomSync, + insertType: EventInsertType, + syncLocalTimestampMillis: Long, + aggregator: SyncResponsePostTreatmentAggregator): RoomEntity { Timber.v("Handle join sync for room $roomId") val isInitialSync = insertType == EventInsertType.INITIAL_SYNC @@ -353,15 +353,15 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle return roomEntity } - private suspend fun handleTimelineEvents(realm: Realm, - roomId: String, - roomEntity: RoomEntity, - eventList: List, - prevToken: String? = null, - isLimited: Boolean = true, - insertType: EventInsertType, - syncLocalTimestampMillis: Long, - aggregator: SyncResponsePostTreatmentAggregator): ChunkEntity { + private fun handleTimelineEvents(realm: Realm, + roomId: String, + roomEntity: RoomEntity, + eventList: List, + prevToken: String? = null, + isLimited: Boolean = true, + insertType: EventInsertType, + syncLocalTimestampMillis: Long, + aggregator: SyncResponsePostTreatmentAggregator): ChunkEntity { val lastChunk = ChunkEntity.findLastForwardChunkOfRoom(realm, roomEntity.roomId) if (isLimited && lastChunk != null) { lastChunk.deleteOnCascade(deleteStateEvents = false, canDeleteRoot = true) @@ -389,8 +389,10 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle liveEventService.get().dispatchLiveEventReceived(event, roomId, isInitialSync) if (event.isEncrypted() && !isInitialSync) { - runBlocking { + try { decryptIfNeeded(event, roomId) + } catch (e: InterruptedException) { + Timber.i("Decryption got interrupted") } } var contentToInject: String? = null @@ -421,7 +423,8 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle roomId = roomId, eventEntity = eventEntity, direction = PaginationDirection.FORWARDS, - roomMemberContentsByUser = roomMemberContentsByUser) + roomMemberContentsByUser = roomMemberContentsByUser + ) if (lightweightSettingsStorage.areThreadMessagesEnabled()) { eventEntity.rootThreadEventId?.let { // This is a thread event @@ -437,7 +440,8 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle threadEventEntity = eventEntity, roomMemberContentsByUser = roomMemberContentsByUser, userId = userId, - roomEntity = roomEntity) + roomEntity = roomEntity + ) } } ?: run { // This is a normal event or a root thread one @@ -475,7 +479,8 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle roomId = roomId, realm = realm, chunkEntity = chunkEntity, - currentUserId = userId) + currentUserId = userId + ) } // posting new events to timeline if any is registered @@ -505,10 +510,11 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle } } - private suspend fun decryptIfNeeded(event: Event, roomId: String) { + private fun decryptIfNeeded(event: Event, roomId: String) { try { // Event from sync does not have roomId, so add it to the event first - val result = cryptoService.decryptEvent(event.copy(roomId = roomId), "") + // note: runBlocking should be used here while we are in realm single thread executor, to avoid thread switching + val result = runBlocking { cryptoService.decryptEvent(event.copy(roomId = roomId), "") } event.mxDecryptionResult = OlmDecryptionResult( payload = result.clearEvent, senderKey = result.senderCurve25519Key, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/CreateWidgetTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/CreateWidgetTask.kt index 18a043be45..06508def1c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/CreateWidgetTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/CreateWidgetTask.kt @@ -29,9 +29,10 @@ import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.room.RoomAPI import org.matrix.android.sdk.internal.task.Task +import timber.log.Timber import javax.inject.Inject -internal interface CreateWidgetTask : Task { +internal interface CreateWidgetTask : Task { data class Params( val roomId: String, @@ -45,8 +46,8 @@ internal class DefaultCreateWidgetTask @Inject constructor(@SessionDatabase priv @UserId private val userId: String, private val globalErrorReceiver: GlobalErrorReceiver) : CreateWidgetTask { - override suspend fun execute(params: CreateWidgetTask.Params) { - executeRequest(globalErrorReceiver) { + override suspend fun execute(params: CreateWidgetTask.Params): String { + val response = executeRequest(globalErrorReceiver) { roomAPI.sendStateEvent( roomId = params.roomId, stateEventType = EventType.STATE_ROOM_WIDGET_LEGACY, @@ -60,5 +61,8 @@ internal class DefaultCreateWidgetTask @Inject constructor(@SessionDatabase priv .and() .equalTo(CurrentStateEventEntityFields.ROOT.SENDER, userId) } + return response.eventId.also { + Timber.d("Widget state event: $it just sent in room ${params.roomId}") + } } } diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/api/pushrules/PushRuleActionsTest.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/api/session/pushrules/PushRuleActionsTest.kt similarity index 95% rename from matrix-sdk-android/src/test/java/org/matrix/android/sdk/api/pushrules/PushRuleActionsTest.kt rename to matrix-sdk-android/src/test/java/org/matrix/android/sdk/api/session/pushrules/PushRuleActionsTest.kt index 9bfdea5414..1879e8195c 100644 --- a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/api/pushrules/PushRuleActionsTest.kt +++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/api/session/pushrules/PushRuleActionsTest.kt @@ -14,14 +14,14 @@ * limitations under the License. */ -package org.matrix.android.sdk.api.pushrules +package org.matrix.android.sdk.api.session.pushrules import org.junit.Assert.assertEquals import org.junit.Assert.assertNotNull import org.junit.Assert.assertTrue import org.junit.Test import org.matrix.android.sdk.MatrixTest -import org.matrix.android.sdk.api.pushrules.rest.PushRule +import org.matrix.android.sdk.api.session.pushrules.rest.PushRule import org.matrix.android.sdk.internal.di.MoshiProvider class PushRuleActionsTest : MatrixTest { diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/api/pushrules/PushRulesConditionTest.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/api/session/pushrules/PushRulesConditionTest.kt similarity index 95% rename from matrix-sdk-android/src/test/java/org/matrix/android/sdk/api/pushrules/PushRulesConditionTest.kt rename to matrix-sdk-android/src/test/java/org/matrix/android/sdk/api/session/pushrules/PushRulesConditionTest.kt index c0b869a90e..95787173da 100644 --- a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/api/pushrules/PushRulesConditionTest.kt +++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/api/session/pushrules/PushRulesConditionTest.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.matrix.android.sdk.api.pushrules +package org.matrix.android.sdk.api.session.pushrules import io.mockk.every import io.mockk.mockk @@ -26,6 +26,7 @@ import org.matrix.android.sdk.MatrixTest import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.toContent import org.matrix.android.sdk.api.session.room.Room +import org.matrix.android.sdk.api.session.room.members.MembershipService import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.model.RoomMemberContent import org.matrix.android.sdk.api.session.room.model.message.MessageTextContent @@ -148,14 +149,22 @@ class PushRulesConditionTest : MatrixTest { val room2JoinedId = "2joined" val room3JoinedId = "3joined" - val roomStub2Joined = mockk { + val roomMembershipService2 = mockk { every { getNumberOfJoinedMembers() } returns 2 } - val roomStub3Joined = mockk { + val roomMembershipService3 = mockk { every { getNumberOfJoinedMembers() } returns 3 } + val roomStub2Joined = mockk { + every { membershipService() } returns roomMembershipService2 + } + + val roomStub3Joined = mockk { + every { membershipService() } returns roomMembershipService3 + } + val roomGetterStub = mockk { every { getRoom(room2JoinedId) } returns roomStub2Joined every { getRoom(room3JoinedId) } returns roomStub3Joined diff --git a/vector/src/androidTest/java/im/vector/app/SecurityBootstrapTest.kt b/vector/src/androidTest/java/im/vector/app/SecurityBootstrapTest.kt index 69fe63fb7b..a84aae9994 100644 --- a/vector/src/androidTest/java/im/vector/app/SecurityBootstrapTest.kt +++ b/vector/src/androidTest/java/im/vector/app/SecurityBootstrapTest.kt @@ -166,7 +166,7 @@ class SecurityBootstrapTest : VerificationTestBase() { assert(uiSession.cryptoService().crossSigningService().allPrivateKeysKnown()) assert(uiSession.cryptoService().keysBackupService().isEnabled) assert(uiSession.cryptoService().keysBackupService().currentBackupVersion != null) - assert(uiSession.sharedSecretStorageService.isRecoverySetup()) - assert(uiSession.sharedSecretStorageService.isMegolmKeyInBackup()) + assert(uiSession.sharedSecretStorageService().isRecoverySetup()) + assert(uiSession.sharedSecretStorageService().isMegolmKeyInBackup()) } } diff --git a/vector/src/androidTest/java/im/vector/app/espresso/tools/EspressoPreference.kt b/vector/src/androidTest/java/im/vector/app/espresso/tools/EspressoPreference.kt index 178b9fb9f6..19dc1d391c 100644 --- a/vector/src/androidTest/java/im/vector/app/espresso/tools/EspressoPreference.kt +++ b/vector/src/androidTest/java/im/vector/app/espresso/tools/EspressoPreference.kt @@ -26,6 +26,7 @@ import androidx.test.espresso.action.ViewActions.click import androidx.test.espresso.contrib.RecyclerViewActions.actionOnItem import androidx.test.espresso.matcher.PreferenceMatchers.withKey import androidx.test.espresso.matcher.ViewMatchers.hasDescendant +import androidx.test.espresso.matcher.ViewMatchers.isFocusable import androidx.test.espresso.matcher.ViewMatchers.withClassName import androidx.test.espresso.matcher.ViewMatchers.withId import androidx.test.espresso.matcher.ViewMatchers.withText @@ -36,8 +37,15 @@ import org.hamcrest.Matchers.`is` fun clickOnPreference(@StringRes textResId: Int) { onView(withId(R.id.recycler_view)) - .perform(actionOnItem( - hasDescendant(withText(textResId)), click())) + .perform( + actionOnItem( + allOf( + hasDescendant(withText(textResId)), + // Avoid to click on the Preference Category + isFocusable() + ), click() + ) + ) } fun clickOnSwitchPreference(preferenceKey: String) { diff --git a/vector/src/androidTest/java/im/vector/app/ui/robot/RoomDetailRobot.kt b/vector/src/androidTest/java/im/vector/app/ui/robot/RoomDetailRobot.kt index 0ea1191fba..91409582d9 100644 --- a/vector/src/androidTest/java/im/vector/app/ui/robot/RoomDetailRobot.kt +++ b/vector/src/androidTest/java/im/vector/app/ui/robot/RoomDetailRobot.kt @@ -56,10 +56,8 @@ class RoomDetailRobot { // Menu openMenu() pressBack() - /* TODO something has changed in the menu :/ clickMenu(R.id.voice_call) pressBack() - */ clickMenu(R.id.video_call) pressBack() } diff --git a/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsSecurityRobot.kt b/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsSecurityRobot.kt index ef20d7764b..841c99e1b5 100644 --- a/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsSecurityRobot.kt +++ b/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsSecurityRobot.kt @@ -18,7 +18,6 @@ package im.vector.app.ui.robot.settings import androidx.test.espresso.Espresso import im.vector.app.R -import im.vector.app.clickOnAndGoBack import im.vector.app.espresso.tools.clickOnPreference class SettingsSecurityRobot { @@ -38,10 +37,7 @@ class SettingsSecurityRobot { clickOnPreference(R.string.settings_opt_in_of_analytics) Espresso.pressBack() - ignoredUsers() - } - - private fun ignoredUsers(block: () -> Unit = {}) { - clickOnAndGoBack(R.string.settings_ignored_users) { block() } + clickOnPreference(R.string.settings_ignored_users) + Espresso.pressBack() } } diff --git a/vector/src/gplay/java/im/vector/app/gplay/features/settings/troubleshoot/TestTokenRegistration.kt b/vector/src/gplay/java/im/vector/app/gplay/features/settings/troubleshoot/TestTokenRegistration.kt index f0199ad390..ec1b9ca7a2 100644 --- a/vector/src/gplay/java/im/vector/app/gplay/features/settings/troubleshoot/TestTokenRegistration.kt +++ b/vector/src/gplay/java/im/vector/app/gplay/features/settings/troubleshoot/TestTokenRegistration.kt @@ -49,7 +49,7 @@ class TestTokenRegistration @Inject constructor(private val context: FragmentAct status = TestStatus.FAILED return } - val pushers = session.getPushers().filter { + val pushers = session.pushersService().getPushers().filter { it.pushKey == fcmToken && it.state == PusherState.REGISTERED } if (pushers.isEmpty()) { diff --git a/vector/src/gplay/java/im/vector/app/gplay/push/fcm/VectorFirebaseMessagingService.kt b/vector/src/gplay/java/im/vector/app/gplay/push/fcm/VectorFirebaseMessagingService.kt index 93a82f24f9..b62520278a 100755 --- a/vector/src/gplay/java/im/vector/app/gplay/push/fcm/VectorFirebaseMessagingService.kt +++ b/vector/src/gplay/java/im/vector/app/gplay/push/fcm/VectorFirebaseMessagingService.kt @@ -46,6 +46,8 @@ import kotlinx.coroutines.runBlocking import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.logger.LoggerTag import org.matrix.android.sdk.api.session.Session +import org.matrix.android.sdk.api.session.getRoom +import org.matrix.android.sdk.api.session.room.getTimelineEvent import timber.log.Timber import javax.inject.Inject @@ -194,7 +196,7 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() { coroutineScope.launch { Timber.tag(loggerTag.value).d("Fast lane: start request") - val event = tryOrNull { session.getEvent(roomId, eventId) } ?: return@launch + val event = tryOrNull { session.eventService().getEvent(roomId, eventId) } ?: return@launch val resolvedEvent = notifiableEventResolver.resolveInMemoryEvent(session, event, canBeReplaced = true) diff --git a/vector/src/main/java/im/vector/app/AppStateHandler.kt b/vector/src/main/java/im/vector/app/AppStateHandler.kt index cc3aed03fb..1608d561bc 100644 --- a/vector/src/main/java/im/vector/app/AppStateHandler.kt +++ b/vector/src/main/java/im/vector/app/AppStateHandler.kt @@ -38,6 +38,8 @@ import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.session.Session +import org.matrix.android.sdk.api.session.getRoom +import org.matrix.android.sdk.api.session.getRoomSummary import org.matrix.android.sdk.api.session.group.model.GroupSummary import org.matrix.android.sdk.api.session.initsync.SyncStatusService import org.matrix.android.sdk.api.session.room.model.RoomSummary @@ -78,7 +80,7 @@ class AppStateHandler @Inject constructor( return selectedSpaceDataSource.currentValue?.orNull()?.let { if (it is RoomGroupingMethod.BySpace) { // try to refresh sum? - it.spaceSummary?.roomId?.let { activeSessionHolder.getSafeActiveSession()?.getRoomSummary(it) }?.let { + it.spaceSummary?.roomId?.let { activeSessionHolder.getSafeActiveSession()?.roomService()?.getRoomSummary(it) }?.let { RoomGroupingMethod.BySpace(it) } ?: it } else it @@ -100,7 +102,7 @@ class AppStateHandler @Inject constructor( if (spaceId != null) { uSession.coroutineScope.launch(Dispatchers.IO) { tryOrNull { - uSession.getRoom(spaceId)?.loadRoomMembersIfNeeded() + uSession.getRoom(spaceId)?.membershipService()?.loadRoomMembersIfNeeded() } } } @@ -110,12 +112,12 @@ class AppStateHandler @Inject constructor( val uSession = session ?: activeSessionHolder.getSafeActiveSession() ?: return if (selectedSpaceDataSource.currentValue?.orNull() is RoomGroupingMethod.ByLegacyGroup && groupId == selectedSpaceDataSource.currentValue?.orNull()?.group()?.groupId) return - val activeGroup = groupId?.let { uSession.getGroupSummary(groupId) } + val activeGroup = groupId?.let { uSession.groupService().getGroupSummary(groupId) } selectedSpaceDataSource.post(Option.just(RoomGroupingMethod.ByLegacyGroup(activeGroup))) if (groupId != null) { uSession.coroutineScope.launch { tryOrNull { - uSession.getGroup(groupId)?.fetchGroupData() + uSession.groupService().getGroup(groupId)?.fetchGroupData() } } } @@ -139,7 +141,7 @@ class AppStateHandler @Inject constructor( } private fun observeSyncStatus(session: Session) { - session.getSyncStatusLive() + session.syncStatusService().getSyncStatusLive() .asFlow() .filterIsInstance() .map { session.spaceService().getRootSpaceSummaries().size } diff --git a/vector/src/main/java/im/vector/app/AutoRageShaker.kt b/vector/src/main/java/im/vector/app/AutoRageShaker.kt index 195e2f68dc..c77ce2b647 100644 --- a/vector/src/main/java/im/vector/app/AutoRageShaker.kt +++ b/vector/src/main/java/im/vector/app/AutoRageShaker.kt @@ -169,7 +169,7 @@ class AutoRageShaker @Inject constructor( coroutineScope.launch { try { - activeSessionHolder.getSafeActiveSession()?.sendToDevice( + activeSessionHolder.getSafeActiveSession()?.toDeviceService()?.sendToDevice( eventType = AUTO_RS_REQUEST, userId = target.senderUserId, deviceId = target.senderDeviceId, @@ -261,7 +261,7 @@ class AutoRageShaker @Inject constructor( this.currentActiveSessionId = sessionId hasSynced = session.hasAlreadySynced() - session.getSyncStatusLive() + session.syncStatusService().getSyncStatusLive() .asFlow() .onEach { hasSynced = it !is SyncStatusService.Status.InitialSyncProgressing @@ -269,11 +269,11 @@ class AutoRageShaker @Inject constructor( .launchIn(session.coroutineScope) activeSessionIds.add(sessionId) session.addListener(this) - session.addEventStreamListener(detector) + session.eventStreamService().addEventStreamListener(detector) } override fun onSessionStopped(session: Session) { - session.removeEventStreamListener(detector) + session.eventStreamService().removeEventStreamListener(detector) activeSessionIds.remove(session.sessionId) } } diff --git a/vector/src/main/java/im/vector/app/UISIDetector.kt b/vector/src/main/java/im/vector/app/UISIDetector.kt index fea1861cc6..4a9d8ae266 100644 --- a/vector/src/main/java/im/vector/app/UISIDetector.kt +++ b/vector/src/main/java/im/vector/app/UISIDetector.kt @@ -52,7 +52,7 @@ data class E2EMessageDetected( } } -class UISIDetector : LiveEventListener { +class UISIDetector(private val timeoutMillis: Long = 30_000L) : LiveEventListener { interface UISIDetectorCallback { val enabled: Boolean @@ -66,7 +66,6 @@ class UISIDetector : LiveEventListener { private val trackedEvents = mutableMapOf() private val executor = Executors.newSingleThreadExecutor() private val timer = Timer() - private val timeoutMillis = 30_000L private val enabled: Boolean get() = callback?.enabled.orFalse() override fun onEventDecrypted(event: Event, clearEvent: JsonDict) { @@ -90,22 +89,27 @@ class UISIDetector : LiveEventListener { val roomId = event.roomId if (!enabled || eventId == null || roomId == null) return - val trackerId: String = trackerId(eventId, roomId) - if (trackedEvents.containsKey(trackerId)) { - Timber.w("## UISIDetector: Event $eventId is already tracked") + val trackedId: String = trackedId(eventId, roomId) + if (trackedEvents.containsKey(trackedId)) { + Timber.v("## UISIDetector: Event $eventId is already tracked") return } // track it and start timer val timeoutTask = object : TimerTask() { override fun run() { executor.execute { + // we should check if it's still tracked (it might have been decrypted) + if (!trackedEvents.containsKey(trackedId)) { + Timber.v("## UISIDetector: E2E error for $eventId was resolved") + return@execute + } unTrack(eventId, roomId) Timber.v("## UISIDetector: Timeout on $eventId") triggerUISI(E2EMessageDetected.fromEvent(event, roomId)) } } } - trackedEvents[trackerId] = timeoutTask + trackedEvents[trackedId] = timeoutTask timer.schedule(timeoutTask, timeoutMillis) } @@ -113,7 +117,7 @@ class UISIDetector : LiveEventListener { override fun onPaginatedEvent(roomId: String, event: Event) {} - private fun trackerId(eventId: String, roomId: String): String = "$roomId-$eventId" + private fun trackedId(eventId: String, roomId: String): String = "$roomId-$eventId" private fun triggerUISI(source: E2EMessageDetected) { if (!enabled) return @@ -122,6 +126,6 @@ class UISIDetector : LiveEventListener { } private fun unTrack(eventId: String, roomId: String) { - trackedEvents.remove(trackerId(eventId, roomId))?.cancel() + trackedEvents.remove(trackedId(eventId, roomId))?.cancel() } } diff --git a/vector/src/main/java/im/vector/app/core/extensions/Session.kt b/vector/src/main/java/im/vector/app/core/extensions/Session.kt index f89ba4c47a..9bc1aff868 100644 --- a/vector/src/main/java/im/vector/app/core/extensions/Session.kt +++ b/vector/src/main/java/im/vector/app/core/extensions/Session.kt @@ -30,11 +30,11 @@ import timber.log.Timber fun Session.configureAndStart(context: Context, startSyncing: Boolean = true) { Timber.i("Configure and start session for $myUserId") open() - setFilter(FilterService.FilterPreset.ElementFilter) + filterService().setFilter(FilterService.FilterPreset.ElementFilter) if (startSyncing) { startSyncing(context) } - refreshPushers() + pushersService().refreshPushers() context.singletonEntryPoint().webRtcCallManager().checkForProtocolsSupportIfNeeded() } @@ -75,7 +75,7 @@ fun Session.cannotLogoutSafely(): Boolean { // has local cross signing keys (cryptoService().crossSigningService().allPrivateKeysKnown() && // That are not backed up - !sharedSecretStorageService.isRecoverySetup()) + !sharedSecretStorageService().isRecoverySetup()) } fun Session.vectorStore(context: Context) = VectorSessionStore(context, myUserId) diff --git a/vector/src/main/java/im/vector/app/core/pushers/PushersManager.kt b/vector/src/main/java/im/vector/app/core/pushers/PushersManager.kt index 27d6d05708..b1bb4c7d88 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/PushersManager.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/PushersManager.kt @@ -37,7 +37,7 @@ class PushersManager @Inject constructor( suspend fun testPush(pushKey: String) { val currentSession = activeSessionHolder.getActiveSession() - currentSession.testPush( + currentSession.pushersService().testPush( stringProvider.getString(R.string.pusher_http_url), stringProvider.getString(R.string.pusher_app_id), pushKey, @@ -47,12 +47,12 @@ class PushersManager @Inject constructor( fun enqueueRegisterPusherWithFcmKey(pushKey: String): UUID { val currentSession = activeSessionHolder.getActiveSession() - return currentSession.enqueueAddHttpPusher(createHttpPusher(pushKey)) + return currentSession.pushersService().enqueueAddHttpPusher(createHttpPusher(pushKey)) } suspend fun registerPusherWithFcmKey(pushKey: String) { val currentSession = activeSessionHolder.getActiveSession() - currentSession.addHttpPusher(createHttpPusher(pushKey)) + currentSession.pushersService().addHttpPusher(createHttpPusher(pushKey)) } private fun createHttpPusher(pushKey: String) = PushersService.HttpPusher( @@ -70,7 +70,7 @@ class PushersManager @Inject constructor( suspend fun registerEmailForPush(email: String) { val currentSession = activeSessionHolder.getActiveSession() val appName = appNameProvider.getAppName() - currentSession.addEmailPusher( + currentSession.pushersService().addEmailPusher( email = email, lang = localeProvider.current().language, emailBranding = appName, @@ -81,12 +81,12 @@ class PushersManager @Inject constructor( suspend fun unregisterEmailPusher(email: String) { val currentSession = activeSessionHolder.getSafeActiveSession() ?: return - currentSession.removeEmailPusher(email) + currentSession.pushersService().removeEmailPusher(email) } suspend fun unregisterPusher(pushKey: String) { val currentSession = activeSessionHolder.getSafeActiveSession() ?: return - currentSession.removeHttpPusher(pushKey, stringProvider.getString(R.string.pusher_app_id)) + currentSession.pushersService().removeHttpPusher(pushKey, stringProvider.getString(R.string.pusher_app_id)) } companion object { diff --git a/vector/src/main/java/im/vector/app/core/ui/views/CompatKonfetti.kt b/vector/src/main/java/im/vector/app/core/ui/views/CompatKonfetti.kt new file mode 100644 index 0000000000..6b969fe2a5 --- /dev/null +++ b/vector/src/main/java/im/vector/app/core/ui/views/CompatKonfetti.kt @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.core.ui.views + +import android.content.Context +import android.os.Build +import android.util.AttributeSet +import android.view.View +import nl.dionsegijn.konfetti.xml.KonfettiView + +/** + * Konfetti workaround to avoid crashes on API 21/22 + * https://github.com/DanielMartinus/Konfetti/issues/297 + */ +class CompatKonfetti @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null +) : KonfettiView(context, attrs) { + + override fun onVisibilityChanged(changedView: View, visibility: Int) { + when (Build.VERSION.SDK_INT) { + Build.VERSION_CODES.LOLLIPOP, Build.VERSION_CODES.LOLLIPOP_MR1 -> safeOnVisibilityChanged(changedView, visibility) + else -> super.onVisibilityChanged(changedView, visibility) + } + } + + private fun safeOnVisibilityChanged(changedView: View, visibility: Int) { + runCatching { super.onVisibilityChanged(changedView, visibility) } + } +} diff --git a/vector/src/main/java/im/vector/app/features/MainActivity.kt b/vector/src/main/java/im/vector/app/features/MainActivity.kt index 42bd2318b3..121edd4216 100644 --- a/vector/src/main/java/im/vector/app/features/MainActivity.kt +++ b/vector/src/main/java/im/vector/app/features/MainActivity.kt @@ -160,7 +160,7 @@ class MainActivity : VectorBaseActivity(), UnlockedActivity args.clearCredentials -> { lifecycleScope.launch { try { - session.signOut(!args.isUserLoggedOut) + session.signOutService().signOut(!args.isUserLoggedOut) } catch (failure: Throwable) { displayError(failure) return@launch diff --git a/vector/src/main/java/im/vector/app/features/analytics/DecryptionFailureTracker.kt b/vector/src/main/java/im/vector/app/features/analytics/DecryptionFailureTracker.kt index 6b2ceb1444..ec34ff7421 100644 --- a/vector/src/main/java/im/vector/app/features/analytics/DecryptionFailureTracker.kt +++ b/vector/src/main/java/im/vector/app/features/analytics/DecryptionFailureTracker.kt @@ -38,6 +38,7 @@ private data class DecryptionFailure( val failedEventId: String, val error: MXCryptoError.ErrorType ) +private typealias DetailedErrorName = Pair private const val GRACE_PERIOD_MILLIS = 4_000 private const val CHECK_INTERVAL = 2_000L @@ -112,7 +113,7 @@ class DecryptionFailureTracker @Inject constructor( private fun checkFailures() { val now = clock.epochMillis() - val aggregatedErrors: Map> + val aggregatedErrors: Map> synchronized(failures) { val toReport = mutableListOf() failures.removeAll { failure -> @@ -136,20 +137,21 @@ class DecryptionFailureTracker @Inject constructor( // for now we ignore events already reported even if displayed again? .filter { alreadyReported.contains(it).not() } .forEach { failedEventId -> - analyticsTracker.capture(Error(failedEventId, Error.Domain.E2EE, aggregation.key)) + analyticsTracker.capture(Error(aggregation.key.first, Error.Domain.E2EE, aggregation.key.second)) alreadyReported.add(failedEventId) } } } - private fun MXCryptoError.ErrorType.toAnalyticsErrorName(): Error.Name { - return when (this) { - MXCryptoError.ErrorType.UNKNOWN_INBOUND_SESSION_ID -> Error.Name.OlmKeysNotSentError - MXCryptoError.ErrorType.OLM -> { - Error.Name.OlmUnspecifiedError - } - MXCryptoError.ErrorType.UNKNOWN_MESSAGE_INDEX -> Error.Name.OlmIndexError - else -> Error.Name.UnknownError + private fun MXCryptoError.ErrorType.toAnalyticsErrorName(): DetailedErrorName { + val detailed = "$name | mxc_crypto_error_type" + val errorName = when (this) { + MXCryptoError.ErrorType.UNKNOWN_INBOUND_SESSION_ID, + MXCryptoError.ErrorType.KEYS_WITHHELD -> Error.Name.OlmKeysNotSentError + MXCryptoError.ErrorType.OLM -> Error.Name.OlmUnspecifiedError + MXCryptoError.ErrorType.UNKNOWN_MESSAGE_INDEX -> Error.Name.OlmIndexError + else -> Error.Name.UnknownError } + return DetailedErrorName(detailed, errorName) } } diff --git a/vector/src/main/java/im/vector/app/features/analytics/accountdata/AnalyticsAccountDataViewModel.kt b/vector/src/main/java/im/vector/app/features/analytics/accountdata/AnalyticsAccountDataViewModel.kt index 3b92e7c4de..221a9d8843 100644 --- a/vector/src/main/java/im/vector/app/features/analytics/accountdata/AnalyticsAccountDataViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/analytics/accountdata/AnalyticsAccountDataViewModel.kt @@ -66,7 +66,7 @@ class AnalyticsAccountDataViewModel @AssistedInject constructor( private fun observeInitSync() { combine( - session.getSyncStatusLive().asFlow(), + session.syncStatusService().getSyncStatusLive().asFlow(), analytics.getUserConsent(), analytics.getAnalyticsId() ) { status, userConsent, analyticsId -> diff --git a/vector/src/main/java/im/vector/app/features/analytics/extensions/JoinedRoomExt.kt b/vector/src/main/java/im/vector/app/features/analytics/extensions/JoinedRoomExt.kt index c13f8295f2..27ce3e9a23 100644 --- a/vector/src/main/java/im/vector/app/features/analytics/extensions/JoinedRoomExt.kt +++ b/vector/src/main/java/im/vector/app/features/analytics/extensions/JoinedRoomExt.kt @@ -33,18 +33,20 @@ fun Int?.toAnalyticsRoomSize(): JoinedRoom.RoomSize { } } -fun RoomSummary?.toAnalyticsJoinedRoom(): JoinedRoom { +fun RoomSummary?.toAnalyticsJoinedRoom(trigger: JoinedRoom.Trigger?): JoinedRoom { return JoinedRoom( isDM = this?.isDirect.orFalse(), isSpace = this?.roomType == RoomType.SPACE, - roomSize = this?.joinedMembersCount?.toAnalyticsRoomSize() ?: JoinedRoom.RoomSize.Two + roomSize = this?.joinedMembersCount?.toAnalyticsRoomSize() ?: JoinedRoom.RoomSize.Two, + trigger = trigger ) } -fun PublicRoom.toAnalyticsJoinedRoom(): JoinedRoom { +fun PublicRoom.toAnalyticsJoinedRoom(trigger: JoinedRoom.Trigger?): JoinedRoom { return JoinedRoom( isDM = false, isSpace = false, - roomSize = numJoinedMembers.toAnalyticsRoomSize() + roomSize = numJoinedMembers.toAnalyticsRoomSize(), + trigger = trigger ) } diff --git a/vector/src/main/java/im/vector/app/features/analytics/extensions/ViewRoomExt.kt b/vector/src/main/java/im/vector/app/features/analytics/extensions/ViewRoomExt.kt new file mode 100644 index 0000000000..ada936a3b5 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/analytics/extensions/ViewRoomExt.kt @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.analytics.extensions + +import im.vector.app.RoomGroupingMethod +import im.vector.app.features.analytics.plan.ViewRoom +import org.matrix.android.sdk.api.extensions.orFalse +import org.matrix.android.sdk.api.session.room.model.RoomSummary +import org.matrix.android.sdk.api.session.room.model.RoomType + +fun RoomSummary?.toAnalyticsViewRoom(trigger: ViewRoom.Trigger?, groupingMethod: RoomGroupingMethod? = null, viaKeyboard: Boolean? = null): ViewRoom { + val activeSpace = groupingMethod?.let { + when (it) { + is RoomGroupingMethod.BySpace -> it.spaceSummary?.toActiveSpace() ?: ViewRoom.ActiveSpace.Home + else -> null + } + } + + return ViewRoom( + isDM = this?.isDirect.orFalse(), + isSpace = this?.roomType == RoomType.SPACE, + trigger = trigger, + activeSpace = activeSpace, + viaKeyboard = viaKeyboard + ) +} + +private fun RoomSummary.toActiveSpace(): ViewRoom.ActiveSpace { + return if (isPublic) ViewRoom.ActiveSpace.Public else ViewRoom.ActiveSpace.Private +} diff --git a/vector/src/main/java/im/vector/app/features/analytics/plan/Interaction.kt b/vector/src/main/java/im/vector/app/features/analytics/plan/Interaction.kt index 2007f75fbc..4e4bfe53be 100644 --- a/vector/src/main/java/im/vector/app/features/analytics/plan/Interaction.kt +++ b/vector/src/main/java/im/vector/app/features/analytics/plan/Interaction.kt @@ -87,12 +87,30 @@ data class Interaction( */ WebAddExistingToSpaceDialogCreateRoomButton, + /** + * User clicked the create DM button in the home page of Element + * Web/Desktop. + */ + WebHomeCreateChatButton, + /** * User clicked the create room button in the home page of Element * Web/Desktop. */ WebHomeCreateRoomButton, + /** + * User clicked the explore rooms button in the home page of Element + * Web/Desktop. + */ + WebHomeExploreRoomsButton, + + /** + * User clicked the explore rooms button next to the search field at the + * top of the left panel in Element Web/Desktop. + */ + WebLeftPanelExploreRoomsButton, + /** * User interacted with pin to sidebar checkboxes in the quick settings * menu of Element Web/Desktop. @@ -189,6 +207,12 @@ data class Interaction( */ WebRoomHeaderContextMenuSettingsItem, + /** + * User clicked the create DM button in the + context menu of the room + * list header in Element Web/Desktop. + */ + WebRoomListHeaderPlusMenuCreateChatItem, + /** * User clicked the create room button in the + context menu of the room * list header in Element Web/Desktop. @@ -231,6 +255,12 @@ data class Interaction( */ WebRoomListRoomTileNotificationsMenu, + /** + * User clicked the create DM button in the + context menu of the rooms + * sublist in Element Web/Desktop. + */ + WebRoomListRoomsSublistPlusMenuCreateChatItem, + /** * User clicked the create room button in the + context menu of the * rooms sublist in Element Web/Desktop. diff --git a/vector/src/main/java/im/vector/app/features/analytics/plan/JoinedRoom.kt b/vector/src/main/java/im/vector/app/features/analytics/plan/JoinedRoom.kt index 0011d0e144..06cefa702e 100644 --- a/vector/src/main/java/im/vector/app/features/analytics/plan/JoinedRoom.kt +++ b/vector/src/main/java/im/vector/app/features/analytics/plan/JoinedRoom.kt @@ -49,11 +49,6 @@ data class JoinedRoom( */ Invite, - /** - * Room joined via space explore - */ - MobileExploreRooms, - /** * Room joined via link */ diff --git a/vector/src/main/java/im/vector/app/features/auth/ReAuthViewModel.kt b/vector/src/main/java/im/vector/app/features/auth/ReAuthViewModel.kt index 16aca5cfeb..0bd26870e5 100644 --- a/vector/src/main/java/im/vector/app/features/auth/ReAuthViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/auth/ReAuthViewModel.kt @@ -58,7 +58,7 @@ class ReAuthViewModel @AssistedInject constructor( is ReAuthActions.ReAuthWithPass -> { val safeForIntentCypher = ByteArrayOutputStream().also { it.use { - session.securelyStoreObject(action.password, initialState.resultKeyStoreAlias, it) + session.secureStorageService().securelyStoreObject(action.password, initialState.resultKeyStoreAlias, it) } }.toByteArray().toBase64NoPadding() _viewEvents.post(ReAuthEvents.PasswordFinishSuccess(safeForIntentCypher)) diff --git a/vector/src/main/java/im/vector/app/features/autocomplete/group/AutocompleteGroupPresenter.kt b/vector/src/main/java/im/vector/app/features/autocomplete/group/AutocompleteGroupPresenter.kt index a3c276c977..fc7479eb21 100644 --- a/vector/src/main/java/im/vector/app/features/autocomplete/group/AutocompleteGroupPresenter.kt +++ b/vector/src/main/java/im/vector/app/features/autocomplete/group/AutocompleteGroupPresenter.kt @@ -55,7 +55,7 @@ class AutocompleteGroupPresenter @Inject constructor(context: Context, QueryStringValue.Contains(query.toString(), QueryStringValue.Case.INSENSITIVE) } } - val groups = session.getGroupSummaries(queryParams) + val groups = session.groupService().getGroupSummaries(queryParams) .asSequence() .sortedBy { it.displayName } controller.setData(groups.toList()) diff --git a/vector/src/main/java/im/vector/app/features/autocomplete/member/AutocompleteMemberPresenter.kt b/vector/src/main/java/im/vector/app/features/autocomplete/member/AutocompleteMemberPresenter.kt index ce3b9c6a7e..88d015ec0c 100644 --- a/vector/src/main/java/im/vector/app/features/autocomplete/member/AutocompleteMemberPresenter.kt +++ b/vector/src/main/java/im/vector/app/features/autocomplete/member/AutocompleteMemberPresenter.kt @@ -24,10 +24,11 @@ import dagger.assisted.AssistedInject import im.vector.app.R import im.vector.app.features.autocomplete.AutocompleteClickListener import im.vector.app.features.autocomplete.RecyclerViewPresenter -import org.matrix.android.sdk.api.pushrules.SenderNotificationPermissionCondition import org.matrix.android.sdk.api.query.QueryStringValue import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.events.model.Event +import org.matrix.android.sdk.api.session.getRoom +import org.matrix.android.sdk.api.session.pushrules.SenderNotificationPermissionCondition import org.matrix.android.sdk.api.session.room.members.RoomMemberQueryParams import org.matrix.android.sdk.api.session.room.members.roomMemberQueryParams import org.matrix.android.sdk.api.session.room.model.Membership @@ -126,7 +127,8 @@ class AutocompleteMemberPresenter @AssistedInject constructor(context: Context, ) private fun createMemberItems(queryParams: RoomMemberQueryParams) = - room.getRoomMembers(queryParams) + room.membershipService() + .getRoomMembers(queryParams) .asSequence() .sortedBy { it.displayName } .disambiguate() @@ -147,7 +149,7 @@ class AutocompleteMemberPresenter @AssistedInject constructor(context: Context, AutocompleteMemberItem.Everyone(it) } - private fun canNotifyEveryone() = session.resolveSenderNotificationPermissionCondition( + private fun canNotifyEveryone() = session.pushRuleService().resolveSenderNotificationPermissionCondition( Event( senderId = session.myUserId, roomId = roomId diff --git a/vector/src/main/java/im/vector/app/features/autocomplete/room/AutocompleteRoomPresenter.kt b/vector/src/main/java/im/vector/app/features/autocomplete/room/AutocompleteRoomPresenter.kt index 99f0af7184..d9310e295d 100644 --- a/vector/src/main/java/im/vector/app/features/autocomplete/room/AutocompleteRoomPresenter.kt +++ b/vector/src/main/java/im/vector/app/features/autocomplete/room/AutocompleteRoomPresenter.kt @@ -51,7 +51,7 @@ class AutocompleteRoomPresenter @Inject constructor(context: Context, QueryStringValue.Contains(query.toString(), QueryStringValue.Case.INSENSITIVE) } } - val rooms = session.getRoomSummaries(queryParams) + val rooms = session.roomService().getRoomSummaries(queryParams) .asSequence() .sortedBy { it.displayName } controller.setData(rooms.toList()) diff --git a/vector/src/main/java/im/vector/app/features/call/VectorCallViewModel.kt b/vector/src/main/java/im/vector/app/features/call/VectorCallViewModel.kt index 3b7baef155..55a0219bfe 100644 --- a/vector/src/main/java/im/vector/app/features/call/VectorCallViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/call/VectorCallViewModel.kt @@ -42,6 +42,7 @@ import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.call.CallState import org.matrix.android.sdk.api.session.call.MxCall import org.matrix.android.sdk.api.session.call.MxPeerConnectionState +import org.matrix.android.sdk.api.session.getRoomSummary import org.matrix.android.sdk.api.session.room.model.call.supportCallTransfer import org.matrix.android.sdk.api.util.MatrixItem diff --git a/vector/src/main/java/im/vector/app/features/call/conference/JitsiService.kt b/vector/src/main/java/im/vector/app/features/call/conference/JitsiService.kt index 6fa65bdb7f..07062fc732 100644 --- a/vector/src/main/java/im/vector/app/features/call/conference/JitsiService.kt +++ b/vector/src/main/java/im/vector/app/features/call/conference/JitsiService.kt @@ -31,6 +31,7 @@ import org.jitsi.meet.sdk.JitsiMeetUserInfo import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.raw.RawService import org.matrix.android.sdk.api.session.Session +import org.matrix.android.sdk.api.session.getRoomSummary import org.matrix.android.sdk.api.session.widgets.model.Widget import org.matrix.android.sdk.api.session.widgets.model.WidgetType import org.matrix.android.sdk.api.util.MatrixJsonParser @@ -99,7 +100,7 @@ class JitsiService @Inject constructor( } suspend fun joinConference(roomId: String, jitsiWidget: Widget, enableVideo: Boolean): JitsiCallViewEvents.JoinConference { - val me = session.getRoomMember(session.myUserId, roomId)?.toMatrixItem() + val me = session.roomService().getRoomMember(session.myUserId, roomId)?.toMatrixItem() val userDisplayName = me?.getBestName() val userAvatar = me?.avatarUrl?.let { session.contentUrlResolver().resolveFullSize(it) } val userInfo = JitsiMeetUserInfo().apply { diff --git a/vector/src/main/java/im/vector/app/features/call/dialpad/DialPadLookup.kt b/vector/src/main/java/im/vector/app/features/call/dialpad/DialPadLookup.kt index 80c4e93306..e835a74fd6 100644 --- a/vector/src/main/java/im/vector/app/features/call/dialpad/DialPadLookup.kt +++ b/vector/src/main/java/im/vector/app/features/call/dialpad/DialPadLookup.kt @@ -47,7 +47,7 @@ class DialPadLookup @Inject constructor( if (nativeUserId == session.myUserId) { throw Failure.NumberIsYours } - session.getExistingDirectRoomWithUser(nativeUserId) + session.roomService().getExistingDirectRoomWithUser(nativeUserId) // if there is not, just create a DM with the sip user ?: directRoomHelper.ensureDMExists(sipUserId) } else { diff --git a/vector/src/main/java/im/vector/app/features/call/lookup/CallUserMapper.kt b/vector/src/main/java/im/vector/app/features/call/lookup/CallUserMapper.kt index 0820b34124..eb04ab63d7 100644 --- a/vector/src/main/java/im/vector/app/features/call/lookup/CallUserMapper.kt +++ b/vector/src/main/java/im/vector/app/features/call/lookup/CallUserMapper.kt @@ -20,6 +20,7 @@ import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.events.model.toContent import org.matrix.android.sdk.api.session.events.model.toModel +import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.room.Room import org.matrix.android.sdk.api.session.room.accountdata.RoomAccountDataTypes import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams @@ -29,7 +30,7 @@ class CallUserMapper(private val session: Session, private val protocolsChecker: fun nativeRoomForVirtualRoom(roomId: String): String? { if (!protocolsChecker.supportVirtualRooms) return null val virtualRoom = session.getRoom(roomId) ?: return null - val virtualRoomEvent = virtualRoom.getAccountDataEvent(RoomAccountDataTypes.EVENT_TYPE_VIRTUAL_ROOM) + val virtualRoomEvent = virtualRoom.roomAccountDataService().getAccountDataEvent(RoomAccountDataTypes.EVENT_TYPE_VIRTUAL_ROOM) return virtualRoomEvent?.content?.toModel()?.nativeRoomId } @@ -61,7 +62,7 @@ class CallUserMapper(private val session: Session, private val protocolsChecker: val nativeLookup = session.sipNativeLookup(inviterId).firstOrNull() ?: return if (nativeLookup.fields.containsKey("is_virtual")) { val nativeUser = nativeLookup.userId - val nativeRoomId = session.getExistingDirectRoomWithUser(nativeUser) + val nativeRoomId = session.roomService().getExistingDirectRoomWithUser(nativeUser) if (nativeRoomId != null) { // It's a virtual room with a matching native room, so set the room account data. This // will make sure we know where how to map calls and also allow us know not to display @@ -78,11 +79,11 @@ class CallUserMapper(private val session: Session, private val protocolsChecker: private suspend fun Room.markVirtual(nativeRoomId: String) { val virtualRoomContent = RoomVirtualContent(nativeRoomId = nativeRoomId) - updateAccountData(RoomAccountDataTypes.EVENT_TYPE_VIRTUAL_ROOM, virtualRoomContent.toContent()) + roomAccountDataService().updateAccountData(RoomAccountDataTypes.EVENT_TYPE_VIRTUAL_ROOM, virtualRoomContent.toContent()) } private suspend fun ensureVirtualRoomExists(userId: String, nativeRoomId: String): String { - val existingDMRoom = tryOrNull { session.getExistingDirectRoomWithUser(userId) } + val existingDMRoom = tryOrNull { session.roomService().getExistingDirectRoomWithUser(userId) } val roomId: String if (existingDMRoom != null) { roomId = existingDMRoom @@ -92,7 +93,7 @@ class CallUserMapper(private val session: Session, private val protocolsChecker: setDirectMessage() creationContent[RoomAccountDataTypes.EVENT_TYPE_VIRTUAL_ROOM] = nativeRoomId } - roomId = session.createRoom(roomParams) + roomId = session.roomService().createRoom(roomParams) } return roomId } diff --git a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt index bc8ae51a88..fed61c3b15 100644 --- a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt +++ b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt @@ -989,7 +989,7 @@ class WebRtcCall( val nativeUserId = session.sipNativeLookup(newAssertedIdentity.id!!).firstOrNull()?.userId if (nativeUserId != null) { val resolvedUser = tryOrNull { - session.resolveUser(nativeUserId) + session.userService().resolveUser(nativeUserId) } if (resolvedUser != null) { remoteAssertedIdentity = newAssertedIdentity.copy( diff --git a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCallExt.kt b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCallExt.kt index ac9d169633..de6d5acb20 100644 --- a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCallExt.kt +++ b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCallExt.kt @@ -18,6 +18,7 @@ package im.vector.app.features.call.webrtc import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.session.Session +import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.util.MatrixItem import org.matrix.android.sdk.api.util.toMatrixItem @@ -29,7 +30,7 @@ fun WebRtcCall.getOpponentAsMatrixItem(session: Session): MatrixItem? { roomSummary.toMatrixItem() } else { val userId = roomSummary.otherMemberIds.first() - return room.getRoomMember(userId)?.toMatrixItem() + return room.membershipService().getRoomMember(userId)?.toMatrixItem() } } } diff --git a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt index 0053ab0fc6..25fee28123 100644 --- a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt +++ b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt @@ -43,6 +43,7 @@ import im.vector.app.core.utils.checkPermissions import im.vector.app.core.utils.onPermissionDeniedSnackbar import im.vector.app.core.utils.registerForPermissionsResult import im.vector.app.features.analytics.plan.MobileScreen +import im.vector.app.features.analytics.plan.ViewRoom import im.vector.app.features.contactsbook.ContactsBookFragment import im.vector.app.features.qrcode.QrCodeScannerEvents import im.vector.app.features.qrcode.QrCodeScannerFragment @@ -206,7 +207,11 @@ class CreateDirectRoomActivity : SimpleFragmentActivity() { } private fun renderCreationSuccess(roomId: String) { - navigator.openRoom(this, roomId) + navigator.openRoom( + context = this, + roomId = roomId, + trigger = ViewRoom.Trigger.MessageUser + ) finish() } diff --git a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomViewModel.kt b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomViewModel.kt index 0d67390654..a507f0d099 100644 --- a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomViewModel.kt @@ -36,6 +36,7 @@ import kotlinx.coroutines.launch import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.raw.RawService import org.matrix.android.sdk.api.session.Session +import org.matrix.android.sdk.api.session.getUser import org.matrix.android.sdk.api.session.permalinks.PermalinkData import org.matrix.android.sdk.api.session.permalinks.PermalinkParser import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams @@ -74,7 +75,11 @@ class CreateDirectRoomViewModel @AssistedInject constructor( _viewEvents.post(CreateDirectRoomViewEvents.DmSelf) } else { // Try to get user from known users and fall back to creating a User object from MXID - val qrInvitee = if (session.getUser(mxid) != null) session.getUser(mxid)!! else User(mxid, null, null) + val qrInvitee = if (session.getUser(mxid) != null) { + session.getUser(mxid)!! + } else { + User(mxid, null, null) + } onSubmitInvitees(setOf(PendingSelection.UserPendingSelection(qrInvitee))) } } @@ -85,7 +90,7 @@ class CreateDirectRoomViewModel @AssistedInject constructor( */ private fun onSubmitInvitees(selections: Set) { val existingRoomId = selections.singleOrNull()?.getMxId()?.let { userId -> - session.getExistingDirectRoomWithUser(userId) + session.roomService().getExistingDirectRoomWithUser(userId) } if (existingRoomId != null) { // Do not create a new DM, just tell that the creation is successful by passing the existing roomId @@ -119,7 +124,7 @@ class CreateDirectRoomViewModel @AssistedInject constructor( } val result = runCatchingToAsync { - session.createRoom(roomParams) + session.roomService().createRoom(roomParams) } analyticsTracker.capture(CreatedRoom(isDM = roomParams.isDirect.orFalse())) diff --git a/vector/src/main/java/im/vector/app/features/createdirect/DirectRoomHelper.kt b/vector/src/main/java/im/vector/app/features/createdirect/DirectRoomHelper.kt index e9f0cbfea4..de2027f2a5 100644 --- a/vector/src/main/java/im/vector/app/features/createdirect/DirectRoomHelper.kt +++ b/vector/src/main/java/im/vector/app/features/createdirect/DirectRoomHelper.kt @@ -34,7 +34,7 @@ class DirectRoomHelper @Inject constructor( ) { suspend fun ensureDMExists(userId: String): String { - val existingRoomId = tryOrNull { session.getExistingDirectRoomWithUser(userId) } + val existingRoomId = tryOrNull { session.roomService().getExistingDirectRoomWithUser(userId) } val roomId: String if (existingRoomId != null) { roomId = existingRoomId @@ -48,7 +48,7 @@ class DirectRoomHelper @Inject constructor( setDirectMessage() enableEncryptionIfInvitedUsersSupportIt = adminE2EByDefault } - roomId = session.createRoom(roomParams) + roomId = session.roomService().createRoom(roomParams) analyticsTracker.capture(CreatedRoom(isDM = roomParams.isDirect.orFalse())) } return roomId diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreSharedViewModel.kt b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreSharedViewModel.kt index cf684680ba..6cfe0bf686 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreSharedViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreSharedViewModel.kt @@ -170,7 +170,7 @@ class KeysBackupRestoreSharedViewModel @Inject constructor( fun handleGotSecretFromSSSS(cipherData: String, alias: String) { try { cipherData.fromBase64().inputStream().use { ins -> - val res = session.loadSecureSecret>(ins, alias) + val res = session.secureStorageService().loadSecureSecret>(ins, alias) val secret = res?.get(KEYBACKUP_SECRET_SSSS_NAME) if (secret == null) { _navigateEvent.postValue( @@ -252,7 +252,7 @@ class KeysBackupRestoreSharedViewModel @Inject constructor( ?: return false // Some sanity ? - val defaultKeyResult = session.sharedSecretStorageService.getDefaultKey() + val defaultKeyResult = session.sharedSecretStorageService().getDefaultKey() val keyInfo = (defaultKeyResult as? KeyInfoResult.Success)?.keyInfo ?: return false diff --git a/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecureStorageViewModel.kt b/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecureStorageViewModel.kt index 55ab672c43..445cc70527 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecureStorageViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecureStorageViewModel.kt @@ -87,7 +87,7 @@ class SharedSecureStorageViewModel @AssistedInject constructor( setState { copy(userId = session.myUserId) } - val integrityResult = session.sharedSecretStorageService.checkShouldBeAbleToAccessSecrets(initialState.requestedSecrets, initialState.keyId) + val integrityResult = session.sharedSecretStorageService().checkShouldBeAbleToAccessSecrets(initialState.requestedSecrets, initialState.keyId) if (integrityResult !is IntegrityResult.Success) { _viewEvents.post( SharedSecureStorageViewEvent.Error( @@ -96,8 +96,8 @@ class SharedSecureStorageViewModel @AssistedInject constructor( ) ) } - val keyResult = initialState.keyId?.let { session.sharedSecretStorageService.getKey(it) } - ?: session.sharedSecretStorageService.getDefaultKey() + val keyResult = initialState.keyId?.let { session.sharedSecretStorageService().getKey(it) } + ?: session.sharedSecretStorageService().getDefaultKey() if (!keyResult.isSuccess()) { _viewEvents.post(SharedSecureStorageViewEvent.Dismiss) @@ -205,7 +205,7 @@ class SharedSecureStorageViewModel @AssistedInject constructor( viewModelScope.launch(Dispatchers.IO) { runCatching { val recoveryKey = action.recoveryKey - val keyInfoResult = session.sharedSecretStorageService.getDefaultKey() + val keyInfoResult = session.sharedSecretStorageService().getDefaultKey() if (!keyInfoResult.isSuccess()) { _viewEvents.post(SharedSecureStorageViewEvent.HideModalLoading) _viewEvents.post(SharedSecureStorageViewEvent.Error(stringProvider.getString(R.string.failed_to_access_secure_storage))) @@ -228,7 +228,7 @@ class SharedSecureStorageViewModel @AssistedInject constructor( withContext(Dispatchers.IO) { initialState.requestedSecrets.forEach { if (session.accountDataService().getUserAccountDataEvent(it) != null) { - val res = session.sharedSecretStorageService.getSecret( + val res = session.sharedSecretStorageService().getSecret( name = it, keyId = keyInfo.id, secretKey = keySpec) @@ -243,7 +243,7 @@ class SharedSecureStorageViewModel @AssistedInject constructor( _viewEvents.post(SharedSecureStorageViewEvent.HideModalLoading) val safeForIntentCypher = ByteArrayOutputStream().also { it.use { - session.securelyStoreObject(decryptedSecretMap as Map, initialState.resultKeyStoreAlias, it) + session.secureStorageService().securelyStoreObject(decryptedSecretMap as Map, initialState.resultKeyStoreAlias, it) } }.toByteArray().toBase64NoPadding() _viewEvents.post(SharedSecureStorageViewEvent.FinishSuccess(safeForIntentCypher)) @@ -262,7 +262,7 @@ class SharedSecureStorageViewModel @AssistedInject constructor( viewModelScope.launch(Dispatchers.IO) { runCatching { val passphrase = action.passphrase - val keyInfoResult = session.sharedSecretStorageService.getDefaultKey() + val keyInfoResult = session.sharedSecretStorageService().getDefaultKey() if (!keyInfoResult.isSuccess()) { _viewEvents.post(SharedSecureStorageViewEvent.HideModalLoading) _viewEvents.post(SharedSecureStorageViewEvent.Error("Cannot find ssss key")) @@ -297,7 +297,7 @@ class SharedSecureStorageViewModel @AssistedInject constructor( withContext(Dispatchers.IO) { initialState.requestedSecrets.forEach { if (session.accountDataService().getUserAccountDataEvent(it) != null) { - val res = session.sharedSecretStorageService.getSecret( + val res = session.sharedSecretStorageService().getSecret( name = it, keyId = keyInfo.id, secretKey = keySpec) @@ -312,7 +312,7 @@ class SharedSecureStorageViewModel @AssistedInject constructor( _viewEvents.post(SharedSecureStorageViewEvent.HideModalLoading) val safeForIntentCypher = ByteArrayOutputStream().also { it.use { - session.securelyStoreObject(decryptedSecretMap as Map, initialState.resultKeyStoreAlias, it) + session.secureStorageService().securelyStoreObject(decryptedSecretMap as Map, initialState.resultKeyStoreAlias, it) } }.toByteArray().toBase64NoPadding() _viewEvents.post(SharedSecureStorageViewEvent.FinishSuccess(safeForIntentCypher)) diff --git a/vector/src/main/java/im/vector/app/features/crypto/recover/BackupToQuadSMigrationTask.kt b/vector/src/main/java/im/vector/app/features/crypto/recover/BackupToQuadSMigrationTask.kt index 1767a9444d..2092fe0f00 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/recover/BackupToQuadSMigrationTask.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/recover/BackupToQuadSMigrationTask.kt @@ -61,7 +61,7 @@ class BackupToQuadSMigrationTask @Inject constructor( // We need to use the current secret for keybackup and use it as the new master key for SSSS // Then we need to put back the backup key in sss val keysBackupService = session.cryptoService().keysBackupService() - val quadS = session.sharedSecretStorageService + val quadS = session.sharedSecretStorageService() val version = keysBackupService.keysBackupVersion ?: return Result.NoKeyBackupVersion diff --git a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapCrossSigningTask.kt b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapCrossSigningTask.kt index f65999b945..753e9f1942 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapCrossSigningTask.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapCrossSigningTask.kt @@ -117,7 +117,7 @@ class BootstrapCrossSigningTask @Inject constructor( val keyInfo: SsssKeyCreationInfo - val ssssService = session.sharedSecretStorageService + val ssssService = session.sharedSecretStorageService() params.progressListener?.onProgress( WaitingViewData( diff --git a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSharedViewModel.kt b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSharedViewModel.kt index 1b69b3a919..a85c318a29 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSharedViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSharedViewModel.kt @@ -246,7 +246,8 @@ class BootstrapSharedViewModel @AssistedInject constructor( uiaContinuation?.resume(DefaultBaseAuth(session = pendingAuth?.session ?: "")) } is BootstrapActions.PasswordAuthDone -> { - val decryptedPass = session.loadSecureSecret(action.password.fromBase64().inputStream(), ReAuthActivity.DEFAULT_RESULT_KEYSTORE_ALIAS) + val decryptedPass = session.secureStorageService() + .loadSecureSecret(action.password.fromBase64().inputStream(), ReAuthActivity.DEFAULT_RESULT_KEYSTORE_ALIAS) uiaContinuation?.resume( UserPasswordAuth( session = pendingAuth?.session, diff --git a/vector/src/main/java/im/vector/app/features/crypto/verification/IncomingVerificationRequestHandler.kt b/vector/src/main/java/im/vector/app/features/crypto/verification/IncomingVerificationRequestHandler.kt index 62affec7b5..a57159075f 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/verification/IncomingVerificationRequestHandler.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/verification/IncomingVerificationRequestHandler.kt @@ -18,6 +18,7 @@ package im.vector.app.features.crypto.verification import android.content.Context import im.vector.app.R import im.vector.app.core.platform.VectorBaseActivity +import im.vector.app.features.analytics.plan.ViewRoom import im.vector.app.features.displayname.getBestName import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.home.room.detail.RoomDetailActivity @@ -63,7 +64,7 @@ class IncomingVerificationRequestHandler @Inject constructor( when (tx.state) { is VerificationTxState.OnStarted -> { // Add a notification for every incoming request - val user = session?.getUser(tx.otherUserId) + val user = session?.userService()?.getUser(tx.otherUserId) val name = user?.toMatrixItem()?.getBestName() ?: tx.otherUserId val alert = VerificationVectorAlert( uid, @@ -127,7 +128,7 @@ class IncomingVerificationRequestHandler @Inject constructor( // XXX this is a bit hard coded :/ popupAlertManager.cancelAlert("review_login") } - val user = session?.getUser(pr.otherUserId)?.toMatrixItem() + val user = session?.userService()?.getUser(pr.otherUserId)?.toMatrixItem() val name = user?.getBestName() ?: pr.otherUserId val description = if (name == pr.otherUserId) { name @@ -156,7 +157,12 @@ class IncomingVerificationRequestHandler @Inject constructor( if (roomId.isNullOrBlank()) { it.navigator.waitSessionVerification(it) } else { - it.navigator.openRoom(it, roomId, pr.transactionId) + it.navigator.openRoom( + context = it, + roomId = roomId, + eventId = pr.transactionId, + trigger = ViewRoom.Trigger.VerificationRequest + ) } } } diff --git a/vector/src/main/java/im/vector/app/features/crypto/verification/VerificationBottomSheetViewModel.kt b/vector/src/main/java/im/vector/app/features/crypto/verification/VerificationBottomSheetViewModel.kt index b389a831da..a7998dc474 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/verification/VerificationBottomSheetViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/verification/VerificationBottomSheetViewModel.kt @@ -53,6 +53,7 @@ import org.matrix.android.sdk.api.session.crypto.verification.VerificationServic import org.matrix.android.sdk.api.session.crypto.verification.VerificationTransaction import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxState import org.matrix.android.sdk.api.session.events.model.LocalEcho +import org.matrix.android.sdk.api.session.getUser import org.matrix.android.sdk.api.util.MatrixItem import org.matrix.android.sdk.api.util.awaitCallback import org.matrix.android.sdk.api.util.fromBase64 @@ -149,7 +150,7 @@ class VerificationBottomSheetViewModel @AssistedInject constructor( pendingRequest = if (pr != null) Success(pr) else Uninitialized, isMe = initialState.otherUserId == session.myUserId, currentDeviceCanCrossSign = session.cryptoService().crossSigningService().canCrossSign(), - quadSContainsSecrets = session.sharedSecretStorageService.isRecoverySetup(), + quadSContainsSecrets = session.sharedSecretStorageService().isRecoverySetup(), hasAnyOtherSession = hasAnyOtherSession ) } @@ -231,7 +232,7 @@ class VerificationBottomSheetViewModel @AssistedInject constructor( override fun handle(action: VerificationAction) = withState { state -> val otherUserId = state.otherUserMxItem?.id ?: return@withState val roomId = state.roomId - ?: session.getExistingDirectRoomWithUser(otherUserId) + ?: session.roomService().getExistingDirectRoomWithUser(otherUserId) when (action) { is VerificationAction.RequestVerificationByDM -> { @@ -244,7 +245,7 @@ class VerificationBottomSheetViewModel @AssistedInject constructor( ) } viewModelScope.launch { - val result = runCatching { session.createDirectRoom(otherUserId) } + val result = runCatching { session.roomService().createDirectRoom(otherUserId) } result.fold( { data -> setState { @@ -372,7 +373,7 @@ class VerificationBottomSheetViewModel @AssistedInject constructor( viewModelScope.launch(Dispatchers.IO) { try { action.cypherData.fromBase64().inputStream().use { ins -> - val res = session.loadSecureSecret>(ins, action.alias) + val res = session.secureStorageService().loadSecureSecret>(ins, action.alias) val trustResult = session.cryptoService().crossSigningService().checkTrustFromPrivateKeys( res?.get(MASTER_KEY_SSSS_NAME), res?.get(USER_SIGNING_KEY_SSSS_NAME), diff --git a/vector/src/main/java/im/vector/app/features/crypto/verification/emoji/VerificationEmojiCodeViewModel.kt b/vector/src/main/java/im/vector/app/features/crypto/verification/emoji/VerificationEmojiCodeViewModel.kt index aec28f898e..4b59e2e6fb 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/verification/emoji/VerificationEmojiCodeViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/verification/emoji/VerificationEmojiCodeViewModel.kt @@ -40,6 +40,7 @@ import org.matrix.android.sdk.api.session.crypto.verification.SasVerificationTra import org.matrix.android.sdk.api.session.crypto.verification.VerificationService import org.matrix.android.sdk.api.session.crypto.verification.VerificationTransaction import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxState +import org.matrix.android.sdk.api.session.getUser import org.matrix.android.sdk.api.util.MatrixItem import org.matrix.android.sdk.api.util.toMatrixItem diff --git a/vector/src/main/java/im/vector/app/features/devtools/RoomDevToolViewModel.kt b/vector/src/main/java/im/vector/app/features/devtools/RoomDevToolViewModel.kt index c13ef2f81c..fb78f8581a 100644 --- a/vector/src/main/java/im/vector/app/features/devtools/RoomDevToolViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/devtools/RoomDevToolViewModel.kt @@ -36,6 +36,7 @@ import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.toModel +import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.room.model.message.MessageContent import org.matrix.android.sdk.api.util.JsonDict import org.matrix.android.sdk.api.util.MatrixJsonParser @@ -173,11 +174,10 @@ class RoomDevToolViewModel @AssistedInject constructor( val json = adapter.fromJson(state.editedContent ?: "") ?: throw IllegalArgumentException(stringProvider.getString(R.string.dev_tools_error_no_content)) - room.sendStateEvent( + room.stateService().sendStateEvent( state.selectedEvent?.type.orEmpty(), state.selectedEvent?.stateKey.orEmpty(), json - ) _viewEvents.post(DevToolsViewEvents.ShowSnackMessage(stringProvider.getString(R.string.dev_tools_success_state_event))) setState { @@ -211,7 +211,7 @@ class RoomDevToolViewModel @AssistedInject constructor( ?: throw IllegalArgumentException(stringProvider.getString(R.string.dev_tools_error_no_message_type)) if (isState) { - room.sendStateEvent( + room.stateService().sendStateEvent( eventType, state.sendEventDraft.stateKey.orEmpty(), json @@ -221,7 +221,7 @@ class RoomDevToolViewModel @AssistedInject constructor( // val validParse = MoshiProvider.providesMoshi().adapter(MessageContent::class.java).fromJson(it.sendEventDraft.content ?: "") json.toModel(catchError = false) ?: throw IllegalArgumentException(stringProvider.getString(R.string.dev_tools_error_malformed_event)) - room.sendEvent( + room.sendService().sendEvent( eventType, json ) diff --git a/vector/src/main/java/im/vector/app/features/discovery/DiscoverySettingsViewModel.kt b/vector/src/main/java/im/vector/app/features/discovery/DiscoverySettingsViewModel.kt index 8c1caaf67a..47151223a4 100644 --- a/vector/src/main/java/im/vector/app/features/discovery/DiscoverySettingsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/discovery/DiscoverySettingsViewModel.kt @@ -290,7 +290,7 @@ class DiscoverySettingsViewModel @AssistedInject constructor( } private fun retrieveBinding() { - retrieveBinding(session.getThreePids()) + retrieveBinding(session.profileService().getThreePids()) } private fun retrieveBinding(threePids: List) = withState { state -> diff --git a/vector/src/main/java/im/vector/app/features/discovery/Extensions.kt b/vector/src/main/java/im/vector/app/features/discovery/Extensions.kt index 904b152661..dc25a35646 100644 --- a/vector/src/main/java/im/vector/app/features/discovery/Extensions.kt +++ b/vector/src/main/java/im/vector/app/features/discovery/Extensions.kt @@ -24,7 +24,7 @@ import org.matrix.android.sdk.api.session.terms.TermsService suspend fun Session.fetchIdentityServerWithTerms(userLanguage: String): ServerAndPolicies? { return identityService().getCurrentIdentityServerUrl() ?.let { identityServerUrl -> - val termsResponse = getTerms(TermsService.ServiceType.IdentityService, identityServerUrl.ensureProtocol()) + val termsResponse = termsService().getTerms(TermsService.ServiceType.IdentityService, identityServerUrl.ensureProtocol()) .serverResponse buildServerAndPolicies(identityServerUrl, termsResponse, userLanguage) } @@ -32,7 +32,7 @@ suspend fun Session.fetchIdentityServerWithTerms(userLanguage: String): ServerAn suspend fun Session.fetchHomeserverWithTerms(userLanguage: String): ServerAndPolicies { val homeserverUrl = sessionParams.homeServerUrl - val terms = getHomeserverTerms(homeserverUrl.ensureProtocol()) + val terms = termsService().getHomeserverTerms(homeserverUrl.ensureProtocol()) return buildServerAndPolicies(homeserverUrl, terms, userLanguage) } diff --git a/vector/src/main/java/im/vector/app/features/discovery/change/SetIdentityServerViewModel.kt b/vector/src/main/java/im/vector/app/features/discovery/change/SetIdentityServerViewModel.kt index 4249e8d899..ae1c7f7753 100644 --- a/vector/src/main/java/im/vector/app/features/discovery/change/SetIdentityServerViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/discovery/change/SetIdentityServerViewModel.kt @@ -107,7 +107,7 @@ class SetIdentityServerViewModel @AssistedInject constructor( private suspend fun checkTerms(baseUrl: String) { try { - val data = mxSession.getTerms(TermsService.ServiceType.IdentityService, baseUrl) + val data = mxSession.termsService().getTerms(TermsService.ServiceType.IdentityService, baseUrl) // has all been accepted? val resp = data.serverResponse diff --git a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt index d0ae7581be..12ae67fe6e 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt @@ -49,8 +49,10 @@ import im.vector.app.features.MainActivity import im.vector.app.features.MainActivityArgs import im.vector.app.features.analytics.accountdata.AnalyticsAccountDataViewModel import im.vector.app.features.analytics.plan.MobileScreen +import im.vector.app.features.analytics.plan.ViewRoom import im.vector.app.features.disclaimer.showDisclaimerDialog import im.vector.app.features.matrixto.MatrixToBottomSheet +import im.vector.app.features.matrixto.OriginOfMatrixTo import im.vector.app.features.navigation.Navigator import im.vector.app.features.notifications.NotificationDrawerManager import im.vector.app.features.permalink.NavigationInterceptor @@ -243,7 +245,7 @@ class HomeActivity : } if (args?.inviteNotificationRoomId != null) { activeSessionHolder.getSafeActiveSession()?.permalinkService()?.createPermalink(args.inviteNotificationRoomId)?.let { - navigator.openMatrixToBottomSheet(this, it) + navigator.openMatrixToBottomSheet(this, it, OriginOfMatrixTo.NOTIFICATION) } } @@ -480,7 +482,7 @@ class HomeActivity : activeSessionHolder.getSafeActiveSession() ?.permalinkService() ?.createPermalink(parcelableExtra.inviteNotificationRoomId)?.let { - navigator.openMatrixToBottomSheet(this, it) + navigator.openMatrixToBottomSheet(this, it, OriginOfMatrixTo.NOTIFICATION) } } handleIntent(intent) @@ -567,14 +569,14 @@ class HomeActivity : override fun navToMemberProfile(userId: String, deepLink: Uri): Boolean { // TODO check if there is already one?? - MatrixToBottomSheet.withLink(deepLink.toString()) + MatrixToBottomSheet.withLink(deepLink.toString(), OriginOfMatrixTo.LINK) .show(supportFragmentManager, "HA#MatrixToBottomSheet") return true } override fun navToRoom(roomId: String?, eventId: String?, deepLink: Uri?, rootThreadEventId: String?): Boolean { if (roomId == null) return false - MatrixToBottomSheet.withLink(deepLink.toString()) + MatrixToBottomSheet.withLink(deepLink.toString(), OriginOfMatrixTo.LINK) .show(supportFragmentManager, "HA#MatrixToBottomSheet") return true } @@ -608,8 +610,8 @@ class HomeActivity : } } - override fun mxToBottomSheetNavigateToRoom(roomId: String) { - navigator.openRoom(this, roomId) + override fun mxToBottomSheetNavigateToRoom(roomId: String, trigger: ViewRoom.Trigger?) { + navigator.openRoom(this, roomId, trigger = trigger) } override fun mxToBottomSheetSwitchToSpace(spaceId: String) { diff --git a/vector/src/main/java/im/vector/app/features/home/HomeActivityViewModel.kt b/vector/src/main/java/im/vector/app/features/home/HomeActivityViewModel.kt index 09ca30363c..f0e27e2ee7 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeActivityViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeActivityViewModel.kt @@ -42,10 +42,11 @@ import org.matrix.android.sdk.api.auth.data.LoginFlowTypes import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse import org.matrix.android.sdk.api.auth.registration.nextUncompletedStage import org.matrix.android.sdk.api.extensions.tryOrNull -import org.matrix.android.sdk.api.pushrules.RuleIds import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo import org.matrix.android.sdk.api.session.crypto.model.MXUsersDevicesMap +import org.matrix.android.sdk.api.session.getUser import org.matrix.android.sdk.api.session.initsync.SyncStatusService +import org.matrix.android.sdk.api.session.pushrules.RuleIds import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams import org.matrix.android.sdk.api.settings.LightweightSettingsStorage @@ -175,7 +176,7 @@ class HomeActivityViewModel @AssistedInject constructor( private fun observeInitialSync() { val session = activeSessionHolder.getSafeActiveSession() ?: return - session.getSyncStatusLive() + session.syncStatusService().getSyncStatusLive() .asFlow() .onEach { status -> when (status) { @@ -215,13 +216,16 @@ class HomeActivityViewModel @AssistedInject constructor( if (!vectorPreferences.areNotificationEnabledForDevice()) { // Check if set at account level val mRuleMaster = activeSessionHolder.getSafeActiveSession() + ?.pushRuleService() ?.getPushRules() ?.getAllRules() ?.find { it.ruleId == RuleIds.RULE_ID_DISABLE_ALL } if (mRuleMaster?.enabled == false) { // So push are enabled at account level but not for this session // Let's check that there are some rooms? - val knownRooms = activeSessionHolder.getSafeActiveSession()?.getRoomSummaries(roomSummaryQueryParams { + val knownRooms = activeSessionHolder.getSafeActiveSession() + ?.roomService() + ?.getRoomSummaries(roomSummaryQueryParams { memberships = Membership.activeMemberships() })?.size ?: 0 diff --git a/vector/src/main/java/im/vector/app/features/home/HomeDetailViewModel.kt b/vector/src/main/java/im/vector/app/features/home/HomeDetailViewModel.kt index 2457dd0eaa..fc39165a7e 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeDetailViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeDetailViewModel.kt @@ -91,7 +91,7 @@ class HomeDetailViewModel @AssistedInject constructor( private val refreshRoomSummariesOnCryptoSessionChange = object : NewSessionListener { override fun onNewSession(roomId: String?, senderKey: String, sessionId: String) { - session.refreshJoinedRoomSummaryPreviews(roomId) + session.roomService().refreshJoinedRoomSummaryPreviews(roomId) } } @@ -176,7 +176,7 @@ class HomeDetailViewModel @AssistedInject constructor( private fun handleMarkAllRoomsRead() = withState { _ -> // questionable to use viewmodelscope viewModelScope.launch(Dispatchers.Default) { - val roomIds = session.getRoomSummaries( + val roomIds = session.roomService().getRoomSummaries( roomSummaryQueryParams { memberships = listOf(Membership.JOIN) roomCategoryFilter = RoomCategoryFilter.ONLY_WITH_NOTIFICATIONS @@ -184,7 +184,7 @@ class HomeDetailViewModel @AssistedInject constructor( ) .map { it.roomId } try { - session.markAllAsRead(roomIds) + session.roomService().markAllAsRead(roomIds) } catch (failure: Throwable) { Timber.d(failure, "Failed to mark all as read") } @@ -198,7 +198,7 @@ class HomeDetailViewModel @AssistedInject constructor( copy(syncState = syncState) } - session.getSyncStatusLive() + session.syncStatusService().getSyncStatusLive() .asFlow() .filterIsInstance() .setOnEach { @@ -219,7 +219,7 @@ class HomeDetailViewModel @AssistedInject constructor( appStateHandler.selectedRoomGroupingFlow.distinctUntilChanged().flatMapLatest { // we use it as a trigger to all changes in room, but do not really load // the actual models - session.getPagedRoomSummariesLive( + session.roomService().getPagedRoomSummariesLive( roomSummaryQueryParams { memberships = Membership.activeMemberships() }, @@ -237,7 +237,7 @@ class HomeDetailViewModel @AssistedInject constructor( var dmInvites = 0 var roomsInvite = 0 if (autoAcceptInvites.showInvites()) { - dmInvites = session.getRoomSummaries( + dmInvites = session.roomService().getRoomSummaries( roomSummaryQueryParams { memberships = listOf(Membership.INVITE) roomCategoryFilter = RoomCategoryFilter.ONLY_DM @@ -245,7 +245,7 @@ class HomeDetailViewModel @AssistedInject constructor( } ).size - roomsInvite = session.getRoomSummaries( + roomsInvite = session.roomService().getRoomSummaries( roomSummaryQueryParams { memberships = listOf(Membership.INVITE) roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS @@ -254,7 +254,7 @@ class HomeDetailViewModel @AssistedInject constructor( ).size } - val dmRooms = session.getNotificationCountForRooms( + val dmRooms = session.roomService().getNotificationCountForRooms( roomSummaryQueryParams { memberships = listOf(Membership.JOIN) roomCategoryFilter = RoomCategoryFilter.ONLY_DM @@ -262,7 +262,7 @@ class HomeDetailViewModel @AssistedInject constructor( } ) - val otherRooms = session.getNotificationCountForRooms( + val otherRooms = session.roomService().getNotificationCountForRooms( roomSummaryQueryParams { memberships = listOf(Membership.JOIN) roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS diff --git a/vector/src/main/java/im/vector/app/features/home/HomeDrawerFragment.kt b/vector/src/main/java/im/vector/app/features/home/HomeDrawerFragment.kt index 1aee0257f4..9ce950ba31 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeDrawerFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeDrawerFragment.kt @@ -60,7 +60,7 @@ class HomeDrawerFragment @Inject constructor( if (savedInstanceState == null) { replaceChildFragment(R.id.homeDrawerGroupListContainer, SpaceListFragment::class.java) } - session.getUserLive(session.myUserId).observeK(viewLifecycleOwner) { optionalUser -> + session.userService().getUserLive(session.myUserId).observeK(viewLifecycleOwner) { optionalUser -> val user = optionalUser?.getOrNull() if (user != null) { avatarRenderer.render(user.toMatrixItem(), views.homeDrawerHeaderAvatarView) diff --git a/vector/src/main/java/im/vector/app/features/home/UnknownDeviceDetectorSharedViewModel.kt b/vector/src/main/java/im/vector/app/features/home/UnknownDeviceDetectorSharedViewModel.kt index d2617bd1c8..3ca19b39f9 100644 --- a/vector/src/main/java/im/vector/app/features/home/UnknownDeviceDetectorSharedViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/UnknownDeviceDetectorSharedViewModel.kt @@ -39,6 +39,7 @@ import org.matrix.android.sdk.api.NoOpMatrixCallback import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo +import org.matrix.android.sdk.api.session.getUser import org.matrix.android.sdk.api.util.MatrixItem import org.matrix.android.sdk.api.util.toMatrixItem import org.matrix.android.sdk.flow.flow diff --git a/vector/src/main/java/im/vector/app/features/home/UnreadMessagesSharedViewModel.kt b/vector/src/main/java/im/vector/app/features/home/UnreadMessagesSharedViewModel.kt index 409eb0b845..c1b3937fee 100644 --- a/vector/src/main/java/im/vector/app/features/home/UnreadMessagesSharedViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/UnreadMessagesSharedViewModel.kt @@ -71,9 +71,11 @@ class UnreadMessagesSharedViewModel @AssistedInject constructor(@Assisted initia override fun handle(action: EmptyAction) {} + private val roomService = session.roomService() + init { - session.getPagedRoomSummariesLive( + roomService.getPagedRoomSummariesLive( roomSummaryQueryParams { this.memberships = listOf(Membership.JOIN) this.activeSpaceFilter = ActiveSpaceFilter.ActiveSpace(null) @@ -81,7 +83,7 @@ class UnreadMessagesSharedViewModel @AssistedInject constructor(@Assisted initia ).asFlow() .throttleFirst(300) .execute { - val counts = session.getNotificationCountForRooms( + val counts = roomService.getNotificationCountForRooms( roomSummaryQueryParams { this.memberships = listOf(Membership.JOIN) this.activeSpaceFilter = ActiveSpaceFilter.ActiveSpace(null) @@ -90,7 +92,7 @@ class UnreadMessagesSharedViewModel @AssistedInject constructor(@Assisted initia val invites = if (autoAcceptInvites.hideInvites) { 0 } else { - session.getRoomSummaries( + roomService.getRoomSummaries( roomSummaryQueryParams { this.memberships = listOf(Membership.INVITE) this.activeSpaceFilter = ActiveSpaceFilter.ActiveSpace(null) @@ -109,7 +111,7 @@ class UnreadMessagesSharedViewModel @AssistedInject constructor(@Assisted initia combine( appStateHandler.selectedRoomGroupingFlow.distinctUntilChanged(), appStateHandler.selectedRoomGroupingFlow.flatMapLatest { - session.getPagedRoomSummariesLive( + roomService.getPagedRoomSummariesLive( roomSummaryQueryParams { this.memberships = Membership.activeMemberships() }, sortOrder = RoomSortOrder.NONE @@ -131,7 +133,7 @@ class UnreadMessagesSharedViewModel @AssistedInject constructor(@Assisted initia val inviteCount = if (autoAcceptInvites.hideInvites) { 0 } else { - session.getRoomSummaries( + roomService.getRoomSummaries( roomSummaryQueryParams { this.memberships = listOf(Membership.INVITE) } ).size } @@ -139,14 +141,14 @@ class UnreadMessagesSharedViewModel @AssistedInject constructor(@Assisted initia val spaceInviteCount = if (autoAcceptInvites.hideInvites) { 0 } else { - session.getRoomSummaries( + roomService.getRoomSummaries( spaceSummaryQueryParams { this.memberships = listOf(Membership.INVITE) } ).size } - val totalCount = session.getNotificationCountForRooms( + val totalCount = roomService.getNotificationCountForRooms( roomSummaryQueryParams { this.memberships = listOf(Membership.JOIN) this.activeSpaceFilter = ActiveSpaceFilter.ActiveSpace(null).takeIf { diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailActivity.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailActivity.kt index 5784e6e264..ac4df411a8 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailActivity.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailActivity.kt @@ -36,6 +36,7 @@ import im.vector.app.core.extensions.replaceFragment import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.databinding.ActivityRoomDetailBinding import im.vector.app.features.analytics.plan.MobileScreen +import im.vector.app.features.analytics.plan.ViewRoom import im.vector.app.features.home.room.breadcrumbs.BreadcrumbsFragment import im.vector.app.features.home.room.detail.arguments.TimelineArgs import im.vector.app.features.home.room.detail.timeline.helper.AudioMessagePlaybackTracker @@ -205,8 +206,8 @@ class RoomDetailActivity : } } - override fun mxToBottomSheetNavigateToRoom(roomId: String) { - navigator.openRoom(this, roomId) + override fun mxToBottomSheetNavigateToRoom(roomId: String, trigger: ViewRoom.Trigger?) { + navigator.openRoom(this, roomId, trigger = trigger) } override fun mxToBottomSheetSwitchToSpace(spaceId: String) { diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewState.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewState.kt index 0c56d7e7eb..e01c5ba3b7 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewState.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewState.kt @@ -87,7 +87,12 @@ data class RoomDetailViewState( rootThreadEventId = args.threadTimelineArgs?.rootThreadEventId ) - fun isCallOptionAvailable() = asyncRoomSummary.invoke()?.isDirect ?: true + fun isCallOptionAvailable(): Boolean { + return asyncRoomSummary.invoke()?.isDirect ?: true || + // When there is only one member, a warning will be displayed when the user + // clicks on the menu item to start a call + asyncRoomSummary.invoke()?.joinedMembersCount == 1 + } fun isSearchAvailable() = asyncRoomSummary()?.isEncrypted == false diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt index b79b55b248..7b46eed4f8 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt @@ -40,6 +40,7 @@ import im.vector.app.core.utils.BehaviorDataSource import im.vector.app.features.analytics.AnalyticsTracker import im.vector.app.features.analytics.DecryptionFailureTracker import im.vector.app.features.analytics.extensions.toAnalyticsJoinedRoom +import im.vector.app.features.analytics.plan.JoinedRoom import im.vector.app.features.call.conference.ConferenceEvent import im.vector.app.features.call.conference.JitsiActiveConferenceHolder import im.vector.app.features.call.conference.JitsiService @@ -86,7 +87,10 @@ import org.matrix.android.sdk.api.session.events.model.isTextMessage import org.matrix.android.sdk.api.session.events.model.toContent import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.file.FileService +import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.initsync.SyncStatusService +import org.matrix.android.sdk.api.session.room.getStateEvent +import org.matrix.android.sdk.api.session.room.getTimelineEvent import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState import org.matrix.android.sdk.api.session.room.members.roomMemberQueryParams import org.matrix.android.sdk.api.session.room.model.Membership @@ -181,18 +185,18 @@ class TimelineViewModel @AssistedInject constructor( setupPreviewUrlObservers() room.getRoomSummaryLive() viewModelScope.launch(Dispatchers.IO) { - tryOrNull { room.markAsRead(ReadService.MarkAsReadParams.READ_RECEIPT) } + tryOrNull { room.readService().markAsRead(ReadService.MarkAsReadParams.READ_RECEIPT) } } // Inform the SDK that the room is displayed viewModelScope.launch(Dispatchers.IO) { - tryOrNull { session.onRoomDisplayed(initialState.roomId) } + tryOrNull { session.roomService().onRoomDisplayed(initialState.roomId) } } callManager.addProtocolsCheckerListener(this) callManager.checkForProtocolsSupportIfNeeded() chatEffectManager.delegate = this // Ensure to share the outbound session keys with all members - if (OutboundSessionKeySharingStrategy.WhenEnteringRoom == BuildConfig.outboundSessionKeySharingStrategy && room.isEncrypted()) { + if (OutboundSessionKeySharingStrategy.WhenEnteringRoom == BuildConfig.outboundSessionKeySharingStrategy && room.roomCryptoService().isEncrypted()) { prepareForEncryption() } @@ -248,7 +252,7 @@ class TimelineViewModel @AssistedInject constructor( prepareToEncrypt = Loading() viewModelScope.launch { runCatching { - room.prepareToEncrypt() + room.roomCryptoService().prepareToEncrypt() }.fold({ prepareToEncrypt = Success(Unit) }, { @@ -352,7 +356,7 @@ class TimelineViewModel @AssistedInject constructor( private fun markThreadTimelineAsReadLocal() { initialState.rootThreadEventId?.let { session.coroutineScope.launch { - room.markThreadAsRead(it) + room.threadsLocalService().markThreadAsRead(it) } } } @@ -488,7 +492,7 @@ class TimelineViewModel @AssistedInject constructor( private fun handleSetNewAvatar(action: RoomDetailAction.SetAvatarAction) { viewModelScope.launch(Dispatchers.IO) { try { - room.updateAvatar(action.newAvatarUri, action.newAvatarFileName) + room.stateService().updateAvatar(action.newAvatarUri, action.newAvatarFileName) _viewEvents.post(RoomDetailViewEvents.ActionSuccess(action)) } catch (failure: Throwable) { _viewEvents.post(RoomDetailViewEvents.ActionFailure(action, failure)) @@ -505,7 +509,7 @@ class TimelineViewModel @AssistedInject constructor( } private fun handleJumpToReadReceipt(action: RoomDetailAction.JumpToReadReceipt) { - room.getUserReadReceipt(action.userId) + room.readService().getUserReadReceipt(action.userId) ?.let { handleNavigateToEvent(RoomDetailAction.NavigateToEvent(it, true)) } } @@ -517,7 +521,7 @@ class TimelineViewModel @AssistedInject constructor( eventId = it)) } ?: action.stickerContent - room.sendEvent(EventType.STICKER, content.toContent()) + room.sendService().sendEvent(EventType.STICKER, content.toContent()) } private fun handleStartCall(action: RoomDetailAction.StartCall) { @@ -637,7 +641,7 @@ class TimelineViewModel @AssistedInject constructor( if (trackUnreadMessages.getAndSet(false)) { mostRecentDisplayedEvent?.root?.eventId?.also { session.coroutineScope.launch { - tryOrNull { room.setReadMarker(it) } + tryOrNull { room.readService().setReadMarker(it) } } } mostRecentDisplayedEvent = null @@ -650,12 +654,12 @@ class TimelineViewModel @AssistedInject constructor( } fun getMember(userId: String): RoomMemberSummary? { - return room.getRoomMember(userId) + return room.membershipService().getRoomMember(userId) } private fun handleComposerFocusChange(action: RoomDetailAction.ComposerFocusChange) { // Ensure outbound session keys - if (OutboundSessionKeySharingStrategy.WhenTyping == BuildConfig.outboundSessionKeySharingStrategy && room.isEncrypted()) { + if (OutboundSessionKeySharingStrategy.WhenTyping == BuildConfig.outboundSessionKeySharingStrategy && room.roomCryptoService().isEncrypted()) { if (action.focused) { // Should we add some rate limit here, or do it only once per model lifecycle? prepareForEncryption() @@ -682,7 +686,7 @@ class TimelineViewModel @AssistedInject constructor( } viewModelScope.launch { val result = runCatchingToAsync { - session.joinRoom(roomId, viaServers = viaServers) + session.roomService().joinRoom(roomId, viaServers = viaServers) roomId } setState { @@ -736,36 +740,36 @@ class TimelineViewModel @AssistedInject constructor( // PRIVATE METHODS ***************************************************************************** private fun handleSendReaction(action: RoomDetailAction.SendReaction) { - room.sendReaction(action.targetEventId, action.reaction) + room.relationService().sendReaction(action.targetEventId, action.reaction) } private fun handleRedactEvent(action: RoomDetailAction.RedactAction) { val event = room.getTimelineEvent(action.targetEventId) ?: return - room.redactEvent(event.root, action.reason) + room.sendService().redactEvent(event.root, action.reason) } private fun handleUndoReact(action: RoomDetailAction.UndoReaction) { viewModelScope.launch { tryOrNull { - room.undoReaction(action.targetEventId, action.reaction) + room.relationService().undoReaction(action.targetEventId, action.reaction) } } } private fun handleUpdateQuickReaction(action: RoomDetailAction.UpdateQuickReactAction) { if (action.add) { - room.sendReaction(action.targetEventId, action.selectedReaction) + room.relationService().sendReaction(action.targetEventId, action.selectedReaction) } else { viewModelScope.launch { tryOrNull { - room.undoReaction(action.targetEventId, action.selectedReaction) + room.relationService().undoReaction(action.targetEventId, action.selectedReaction) } } } } private fun handleSendMedia(action: RoomDetailAction.SendMedia) { - room.sendMedias( + room.sendService().sendMedias( action.attachments, action.compressBeforeSending, emptySet(), @@ -808,7 +812,7 @@ class TimelineViewModel @AssistedInject constructor( notificationDrawerManager.updateEvents { it.clearMemberShipNotificationForRoom(initialState.roomId) } viewModelScope.launch { try { - session.leaveRoom(room.roomId) + session.roomService().leaveRoom(room.roomId) } catch (throwable: Throwable) { _viewEvents.post(RoomDetailViewEvents.Failure(throwable, showInDialog = true)) } @@ -819,14 +823,23 @@ class TimelineViewModel @AssistedInject constructor( notificationDrawerManager.updateEvents { it.clearMemberShipNotificationForRoom(initialState.roomId) } viewModelScope.launch { try { - session.joinRoom(room.roomId) - analyticsTracker.capture(room.roomSummary().toAnalyticsJoinedRoom()) + session.roomService().joinRoom(room.roomId) + trackRoomJoined() } catch (throwable: Throwable) { _viewEvents.post(RoomDetailViewEvents.Failure(throwable, showInDialog = true)) } } } + private fun trackRoomJoined() { + val trigger = if (initialState.isInviteAlreadyAccepted) { + JoinedRoom.Trigger.Invite + } else { + JoinedRoom.Trigger.Timeline + } + analyticsTracker.capture(room.roomSummary().toAnalyticsJoinedRoom(trigger)) + } + private fun handleOpenOrDownloadFile(action: RoomDetailAction.DownloadOrOpen) { val mxcUrl = action.messageFileContent.getFileUrl() ?: return val isLocalSendingFile = action.senderId == session.myUserId && @@ -891,8 +904,8 @@ class TimelineViewModel @AssistedInject constructor( return } when { - it.root.isTextMessage() -> room.resendTextMessage(it) - it.root.isAttachmentMessage() -> room.resendMediaMessage(it) + it.root.isTextMessage() -> room.sendService().resendTextMessage(it) + it.root.isAttachmentMessage() -> room.sendService().resendMediaMessage(it) else -> { // TODO } @@ -908,13 +921,13 @@ class TimelineViewModel @AssistedInject constructor( Timber.e("Cannot resend message, it is not failed, Cancel first") return } - room.deleteFailedEcho(it) + room.sendService().deleteFailedEcho(it) } } private fun handleCancel(action: RoomDetailAction.CancelSend) { if (action.force) { - room.cancelSend(action.eventId) + room.sendService().cancelSend(action.eventId) return } val targetEventId = action.eventId @@ -924,16 +937,16 @@ class TimelineViewModel @AssistedInject constructor( Timber.e("Cannot cancel message, it is not sending") return } - room.cancelSend(targetEventId) + room.sendService().cancelSend(targetEventId) } } private fun handleResendAll() { - room.resendAllFailedMessages() + room.sendService().resendAllFailedMessages() } private fun handleRemoveAllFailedMessages() { - room.cancelAllFailedMessages() + room.sendService().cancelAllFailedMessages() } private fun observeEventDisplayedActions() { @@ -956,7 +969,7 @@ class TimelineViewModel @AssistedInject constructor( } bufferedMostRecentDisplayedEvent.root.eventId?.let { eventId -> session.coroutineScope.launch { - tryOrNull { room.setReadReceipt(eventId) } + tryOrNull { room.readService().setReadReceipt(eventId) } } } } @@ -973,14 +986,14 @@ class TimelineViewModel @AssistedInject constructor( private fun handleMarkAllAsRead() { setState { copy(unreadState = UnreadState.HasNoUnread) } viewModelScope.launch { - tryOrNull { room.markAsRead(ReadService.MarkAsReadParams.BOTH) } + tryOrNull { room.readService().markAsRead(ReadService.MarkAsReadParams.BOTH) } } } private fun handleReportContent(action: RoomDetailAction.ReportContent) { viewModelScope.launch { val event = try { - room.reportContent(action.eventId, -100, action.reason) + room.reportingService().reportContent(action.eventId, -100, action.reason) RoomDetailViewEvents.ActionSuccess(action) } catch (failure: Exception) { RoomDetailViewEvents.ActionFailure(action, failure) @@ -996,7 +1009,7 @@ class TimelineViewModel @AssistedInject constructor( viewModelScope.launch { val event = try { - session.ignoreUserIds(listOf(action.userId)) + session.userService().ignoreUserIds(listOf(action.userId)) RoomDetailViewEvents.ActionSuccess(action) } catch (failure: Throwable) { RoomDetailViewEvents.ActionFailure(action, failure) @@ -1070,13 +1083,13 @@ class TimelineViewModel @AssistedInject constructor( room.getTimelineEvent(action.eventId)?.let { pollTimelineEvent -> val currentVote = pollTimelineEvent.annotations?.pollResponseSummary?.aggregatedContent?.myVote if (currentVote != action.optionKey) { - room.voteToPoll(action.eventId, action.optionKey) + room.sendService().voteToPoll(action.eventId, action.optionKey) } } } private fun handleEndPoll(eventId: String) { - room.endPoll(eventId) + room.sendService().endPoll(eventId) } private fun observeSyncState() { @@ -1086,7 +1099,7 @@ class TimelineViewModel @AssistedInject constructor( copy(syncState = syncState) } - session.getSyncStatusLive() + session.syncStatusService().getSyncStatusLive() .asFlow() .filterIsInstance() .setOnEach { @@ -1190,7 +1203,7 @@ class TimelineViewModel @AssistedInject constructor( } if (summary.membership == Membership.INVITE) { summary.inviterId?.let { inviterId -> - session.getRoomMember(inviterId, summary.roomId) + session.roomService().getRoomMember(inviterId, summary.roomId) }?.also { setState { copy(asyncInviter = Success(it)) } } @@ -1254,7 +1267,7 @@ class TimelineViewModel @AssistedInject constructor( timeline.removeAllListeners() decryptionFailureTracker.onTimeLineDisposed(room.roomId) if (vectorPreferences.sendTypingNotifs()) { - room.userStopsTyping() + room.typingService().userStopsTyping() } chatEffectManager.delegate = null chatEffectManager.dispose() diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerViewModel.kt index 9c81a39941..8351af14dc 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerViewModel.kt @@ -28,6 +28,7 @@ import im.vector.app.core.resources.StringProvider import im.vector.app.features.analytics.AnalyticsTracker import im.vector.app.features.analytics.extensions.toAnalyticsComposer import im.vector.app.features.analytics.extensions.toAnalyticsJoinedRoom +import im.vector.app.features.analytics.plan.JoinedRoom import im.vector.app.features.attachments.toContentAttachmentData import im.vector.app.features.command.CommandParser import im.vector.app.features.command.ParsedCommand @@ -50,6 +51,10 @@ import org.matrix.android.sdk.api.session.events.model.getRootThreadEventId import org.matrix.android.sdk.api.session.events.model.isThread import org.matrix.android.sdk.api.session.events.model.toContent import org.matrix.android.sdk.api.session.events.model.toModel +import org.matrix.android.sdk.api.session.getRoom +import org.matrix.android.sdk.api.session.getRoomSummary +import org.matrix.android.sdk.api.session.room.getStateEvent +import org.matrix.android.sdk.api.session.room.getTimelineEvent import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent import org.matrix.android.sdk.api.session.room.model.RoomAvatarContent import org.matrix.android.sdk.api.session.room.model.RoomEncryptionAlgorithm @@ -202,12 +207,12 @@ class MessageComposerViewModel @AssistedInject constructor( is ParsedCommand.ErrorNotACommand -> { // Send the text message to the room if (state.rootThreadEventId != null) { - room.replyInThread( + room.relationService().replyInThread( rootThreadEventId = state.rootThreadEventId, replyInThreadText = action.text, autoMarkdown = action.autoMarkdown) } else { - room.sendTextMessage(action.text, autoMarkdown = action.autoMarkdown) + room.sendService().sendTextMessage(action.text, autoMarkdown = action.autoMarkdown) } _viewEvents.post(MessageComposerViewEvents.MessageSent) @@ -228,12 +233,12 @@ class MessageComposerViewModel @AssistedInject constructor( is ParsedCommand.SendPlainText -> { // Send the text message to the room, without markdown if (state.rootThreadEventId != null) { - room.replyInThread( + room.relationService().replyInThread( rootThreadEventId = state.rootThreadEventId, replyInThreadText = parsedCommand.message, autoMarkdown = false) } else { - room.sendTextMessage(parsedCommand.message, autoMarkdown = false) + room.sendService().sendTextMessage(parsedCommand.message, autoMarkdown = false) } _viewEvents.post(MessageComposerViewEvents.MessageSent) popDraft() @@ -283,13 +288,16 @@ class MessageComposerViewModel @AssistedInject constructor( } is ParsedCommand.SendEmote -> { if (state.rootThreadEventId != null) { - room.replyInThread( + room.relationService().replyInThread( rootThreadEventId = state.rootThreadEventId, replyInThreadText = parsedCommand.message, msgType = MessageType.MSGTYPE_EMOTE, autoMarkdown = action.autoMarkdown) } else { - room.sendTextMessage(parsedCommand.message, msgType = MessageType.MSGTYPE_EMOTE, autoMarkdown = action.autoMarkdown) + room.sendService().sendTextMessage( + text = parsedCommand.message, + msgType = MessageType.MSGTYPE_EMOTE, + autoMarkdown = action.autoMarkdown) } _viewEvents.post(MessageComposerViewEvents.SlashCommandResultOk(parsedCommand)) popDraft() @@ -297,12 +305,12 @@ class MessageComposerViewModel @AssistedInject constructor( is ParsedCommand.SendRainbow -> { val message = parsedCommand.message.toString() if (state.rootThreadEventId != null) { - room.replyInThread( + room.relationService().replyInThread( rootThreadEventId = state.rootThreadEventId, replyInThreadText = parsedCommand.message, formattedText = rainbowGenerator.generate(message)) } else { - room.sendFormattedTextMessage(message, rainbowGenerator.generate(message)) + room.sendService().sendFormattedTextMessage(message, rainbowGenerator.generate(message)) } _viewEvents.post(MessageComposerViewEvents.SlashCommandResultOk(parsedCommand)) popDraft() @@ -310,13 +318,13 @@ class MessageComposerViewModel @AssistedInject constructor( is ParsedCommand.SendRainbowEmote -> { val message = parsedCommand.message.toString() if (state.rootThreadEventId != null) { - room.replyInThread( + room.relationService().replyInThread( rootThreadEventId = state.rootThreadEventId, replyInThreadText = parsedCommand.message, msgType = MessageType.MSGTYPE_EMOTE, formattedText = rainbowGenerator.generate(message)) } else { - room.sendFormattedTextMessage(message, rainbowGenerator.generate(message), MessageType.MSGTYPE_EMOTE) + room.sendService().sendFormattedTextMessage(message, rainbowGenerator.generate(message), MessageType.MSGTYPE_EMOTE) } _viewEvents.post(MessageComposerViewEvents.SlashCommandResultOk(parsedCommand)) @@ -326,12 +334,12 @@ class MessageComposerViewModel @AssistedInject constructor( val text = "[${stringProvider.getString(R.string.spoiler)}](${parsedCommand.message})" val formattedText = "${parsedCommand.message}" if (state.rootThreadEventId != null) { - room.replyInThread( + room.relationService().replyInThread( rootThreadEventId = state.rootThreadEventId, replyInThreadText = text, formattedText = formattedText) } else { - room.sendFormattedTextMessage( + room.sendService().sendFormattedTextMessage( text, formattedText) } @@ -374,7 +382,7 @@ class MessageComposerViewModel @AssistedInject constructor( popDraft() } is ParsedCommand.DiscardSession -> { - if (room.isEncrypted()) { + if (room.roomCryptoService().isEncrypted()) { session.cryptoService().discardOutboundSession(room.roomId) _viewEvents.post(MessageComposerViewEvents.SlashCommandResultOk(parsedCommand)) popDraft() @@ -445,7 +453,7 @@ class MessageComposerViewModel @AssistedInject constructor( is ParsedCommand.LeaveRoom -> { viewModelScope.launch(Dispatchers.IO) { try { - session.leaveRoom(parsedCommand.roomId) + session.roomService().leaveRoom(parsedCommand.roomId) popDraft() _viewEvents.post(MessageComposerViewEvents.SlashCommandResultOk(parsedCommand)) } catch (failure: Throwable) { @@ -486,13 +494,13 @@ class MessageComposerViewModel @AssistedInject constructor( if (inReplyTo != null) { // TODO check if same content? room.getTimelineEvent(inReplyTo)?.let { - room.editReply(state.sendMode.timelineEvent, it, action.text.toString()) + room.relationService().editReply(state.sendMode.timelineEvent, it, action.text.toString()) } } else { val messageContent = state.sendMode.timelineEvent.getLastMessageContent() val existingBody = messageContent?.body ?: "" if (existingBody != action.text) { - room.editTextMessage(state.sendMode.timelineEvent, + room.relationService().editTextMessage(state.sendMode.timelineEvent, messageContent?.msgType ?: MessageType.MSGTYPE_TEXT, action.text, action.autoMarkdown) @@ -504,7 +512,7 @@ class MessageComposerViewModel @AssistedInject constructor( popDraft() } is SendMode.Quote -> { - room.sendQuotedTextMessage( + room.sendService().sendQuotedTextMessage( quotedEvent = state.sendMode.timelineEvent, text = action.text.toString(), autoMarkdown = action.autoMarkdown, @@ -518,12 +526,12 @@ class MessageComposerViewModel @AssistedInject constructor( // If threads are disabled this will make the fallback replies visible to clients with threads enabled val rootThreadEventId = if (showInThread) timelineEvent.root.getRootThreadEventId() else null state.rootThreadEventId?.let { - room.replyInThread( + room.relationService().replyInThread( rootThreadEventId = it, replyInThreadText = action.text.toString(), autoMarkdown = action.autoMarkdown, eventReplied = timelineEvent) - } ?: room.replyToMessage( + } ?: room.relationService().replyToMessage( eventReplied = timelineEvent, replyText = action.text.toString(), autoMarkdown = action.autoMarkdown, @@ -549,13 +557,13 @@ class MessageComposerViewModel @AssistedInject constructor( // Otherwise we clear the composer and remove the draft from db setState { copy(sendMode = SendMode.Regular("", false)) } viewModelScope.launch { - room.deleteDraft() + room.draftService().deleteDraft() } } } private fun loadDraftIfAny() { - val currentDraft = room.getDraft() + val currentDraft = room.draftService().getDraft() setState { copy( // Create a sendMode from a draft and retrieve the TimelineEvent @@ -586,9 +594,9 @@ class MessageComposerViewModel @AssistedInject constructor( private fun handleUserIsTyping(action: MessageComposerAction.UserIsTyping) { if (vectorPreferences.sendTypingNotifs()) { if (action.isTyping) { - room.userIsTyping() + room.typingService().userIsTyping() } else { - room.userStopsTyping() + room.typingService().userStopsTyping() } } } @@ -600,22 +608,22 @@ class MessageComposerViewModel @AssistedInject constructor( ChatEffect.CONFETTI -> R.string.default_message_emote_confetti ChatEffect.SNOWFALL -> R.string.default_message_emote_snow }) - room.sendTextMessage(defaultMessage, MessageType.MSGTYPE_EMOTE) + room.sendService().sendTextMessage(defaultMessage, MessageType.MSGTYPE_EMOTE) } else { - room.sendTextMessage(sendChatEffect.message, sendChatEffect.chatEffect.toMessageType()) + room.sendService().sendTextMessage(sendChatEffect.message, sendChatEffect.chatEffect.toMessageType()) } } private fun handleJoinToAnotherRoomSlashCommand(command: ParsedCommand.JoinRoom) { viewModelScope.launch { try { - session.joinRoom(command.roomAlias, command.reason, emptyList()) + session.roomService().joinRoom(command.roomAlias, command.reason, emptyList()) } catch (failure: Throwable) { _viewEvents.post(MessageComposerViewEvents.SlashCommandResultError(failure)) return@launch } session.getRoomSummary(command.roomAlias) - ?.also { analyticsTracker.capture(it.toAnalyticsJoinedRoom()) } + ?.also { analyticsTracker.capture(it.toAnalyticsJoinedRoom(JoinedRoom.Trigger.SlashCommand)) } ?.roomId ?.let { _viewEvents.post(MessageComposerViewEvents.JoinRoomCommandSuccess(it)) @@ -645,19 +653,19 @@ class MessageComposerViewModel @AssistedInject constructor( private fun handleChangeTopicSlashCommand(changeTopic: ParsedCommand.ChangeTopic) { launchSlashCommandFlowSuspendable(changeTopic) { - room.updateTopic(changeTopic.topic) + room.stateService().updateTopic(changeTopic.topic) } } private fun handleInviteSlashCommand(invite: ParsedCommand.Invite) { launchSlashCommandFlowSuspendable(invite) { - room.invite(invite.userId, invite.reason) + room.membershipService().invite(invite.userId, invite.reason) } } private fun handleInvite3pidSlashCommand(invite: ParsedCommand.Invite3Pid) { launchSlashCommandFlowSuspendable(invite) { - room.invite3pid(invite.threePid) + room.membershipService().invite3pid(invite.threePid) } } @@ -670,13 +678,13 @@ class MessageComposerViewModel @AssistedInject constructor( ?: return launchSlashCommandFlowSuspendable(setUserPowerLevel) { - room.sendStateEvent(EventType.STATE_ROOM_POWER_LEVELS, stateKey = "", newPowerLevelsContent) + room.stateService().sendStateEvent(EventType.STATE_ROOM_POWER_LEVELS, stateKey = "", newPowerLevelsContent) } } private fun handleChangeDisplayNameSlashCommand(changeDisplayName: ParsedCommand.ChangeDisplayName) { launchSlashCommandFlowSuspendable(changeDisplayName) { - session.setDisplayName(session.myUserId, changeDisplayName.displayName) + session.profileService().setDisplayName(session.myUserId, changeDisplayName.displayName) } } @@ -691,32 +699,32 @@ class MessageComposerViewModel @AssistedInject constructor( ?.let { session.getRoom(it) } } ?.let { - session.leaveRoom(it.roomId) + session.roomService().leaveRoom(it.roomId) } } } private fun handleRemoveSlashCommand(removeUser: ParsedCommand.RemoveUser) { launchSlashCommandFlowSuspendable(removeUser) { - room.remove(removeUser.userId, removeUser.reason) + room.membershipService().remove(removeUser.userId, removeUser.reason) } } private fun handleBanSlashCommand(ban: ParsedCommand.BanUser) { launchSlashCommandFlowSuspendable(ban) { - room.ban(ban.userId, ban.reason) + room.membershipService().ban(ban.userId, ban.reason) } } private fun handleUnbanSlashCommand(unban: ParsedCommand.UnbanUser) { launchSlashCommandFlowSuspendable(unban) { - room.unban(unban.userId, unban.reason) + room.membershipService().unban(unban.userId, unban.reason) } } private fun handleChangeRoomNameSlashCommand(changeRoomName: ParsedCommand.ChangeRoomName) { launchSlashCommandFlowSuspendable(changeRoomName) { - room.updateName(changeRoomName.name) + room.stateService().updateName(changeRoomName.name) } } @@ -732,14 +740,14 @@ class MessageComposerViewModel @AssistedInject constructor( ?.copy(displayName = changeDisplayName.displayName) ?.toContent() ?.let { - room.sendStateEvent(EventType.STATE_ROOM_MEMBER, session.myUserId, it) + room.stateService().sendStateEvent(EventType.STATE_ROOM_MEMBER, session.myUserId, it) } } } private fun handleChangeRoomAvatarSlashCommand(changeAvatar: ParsedCommand.ChangeRoomAvatar) { launchSlashCommandFlowSuspendable(changeAvatar) { - room.sendStateEvent(EventType.STATE_ROOM_AVATAR, stateKey = "", RoomAvatarContent(changeAvatar.url).toContent()) + room.stateService().sendStateEvent(EventType.STATE_ROOM_AVATAR, stateKey = "", RoomAvatarContent(changeAvatar.url).toContent()) } } @@ -749,14 +757,14 @@ class MessageComposerViewModel @AssistedInject constructor( ?.copy(avatarUrl = changeAvatar.url) ?.toContent() ?.let { - room.sendStateEvent(EventType.STATE_ROOM_MEMBER, session.myUserId, it) + room.stateService().sendStateEvent(EventType.STATE_ROOM_MEMBER, session.myUserId, it) } } } private fun handleIgnoreSlashCommand(ignore: ParsedCommand.IgnoreUser) { launchSlashCommandFlowSuspendable(ignore) { - session.ignoreUserIds(listOf(ignore.userId)) + session.userService().ignoreUserIds(listOf(ignore.userId)) } } @@ -773,7 +781,7 @@ class MessageComposerViewModel @AssistedInject constructor( private fun handleUnignoreSlashCommandConfirmed(unignore: ParsedCommand.UnignoreUser) { launchSlashCommandFlowSuspendable(unignore) { - session.unIgnoreUserIds(listOf(unignore.userId)) + session.userService().unIgnoreUserIds(listOf(unignore.userId)) } } @@ -790,8 +798,8 @@ class MessageComposerViewModel @AssistedInject constructor( } } rootThreadEventId?.let { - room.replyInThread(it, sequence) - } ?: room.sendTextMessage(sequence) + room.relationService().replyInThread(it, sequence) + } ?: room.sendService().sendTextMessage(sequence) } /** @@ -802,19 +810,19 @@ class MessageComposerViewModel @AssistedInject constructor( when { it.sendMode is SendMode.Regular && !it.sendMode.fromSharing -> { setState { copy(sendMode = it.sendMode.copy(text = draft)) } - room.saveDraft(UserDraft.Regular(draft)) + room.draftService().saveDraft(UserDraft.Regular(draft)) } it.sendMode is SendMode.Reply -> { setState { copy(sendMode = it.sendMode.copy(text = draft)) } - room.saveDraft(UserDraft.Reply(it.sendMode.timelineEvent.root.eventId!!, draft)) + room.draftService().saveDraft(UserDraft.Reply(it.sendMode.timelineEvent.root.eventId!!, draft)) } it.sendMode is SendMode.Quote -> { setState { copy(sendMode = it.sendMode.copy(text = draft)) } - room.saveDraft(UserDraft.Quote(it.sendMode.timelineEvent.root.eventId!!, draft)) + room.draftService().saveDraft(UserDraft.Quote(it.sendMode.timelineEvent.root.eventId!!, draft)) } it.sendMode is SendMode.Edit -> { setState { copy(sendMode = it.sendMode.copy(text = draft)) } - room.saveDraft(UserDraft.Edit(it.sendMode.timelineEvent.root.eventId!!, draft)) + room.draftService().saveDraft(UserDraft.Edit(it.sendMode.timelineEvent.root.eventId!!, draft)) } } } @@ -835,7 +843,7 @@ class MessageComposerViewModel @AssistedInject constructor( } else { audioMessageHelper.stopRecording(convertForSending = true)?.let { audioType -> if (audioType.duration > 1000) { - room.sendMedia( + room.sendService().sendMedia( attachment = audioType.toContentAttachmentData(isVoiceMessage = true), compressBeforeSending = false, roomIds = emptySet(), @@ -902,7 +910,7 @@ class MessageComposerViewModel @AssistedInject constructor( viewModelScope.launch { playingAudioContent?.toContentAttachmentData()?.let { voiceDraft -> val content = voiceDraft.toJsonString() - room.saveDraft(UserDraft.Voice(content)) + room.draftService().saveDraft(UserDraft.Voice(content)) setState { copy(sendMode = SendMode.Voice(content)) } } } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchFragment.kt index b3543ae579..c11fa276f6 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchFragment.kt @@ -37,6 +37,7 @@ import im.vector.app.core.extensions.trackItemsVisibilityChange import im.vector.app.core.platform.StateView import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.databinding.FragmentSearchBinding +import im.vector.app.features.analytics.plan.ViewRoom import im.vector.app.features.home.room.threads.arguments.ThreadTimelineArgs import kotlinx.parcelize.Parcelize import org.matrix.android.sdk.api.session.events.model.Event @@ -134,7 +135,16 @@ class SearchFragment @Inject constructor( roomEncryptionTrustLevel = null, rootThreadEventId = it) navigator.openThread(requireContext(), threadTimelineArgs, event.eventId) - } ?: navigator.openRoom(requireContext(), roomId, event.eventId) + } ?: openRoom(roomId, event.eventId) + } + + private fun openRoom(roomId: String, eventId: String?) { + navigator.openRoom( + context = requireContext(), + roomId = roomId, + eventId = eventId, + trigger = ViewRoom.Trigger.MessageSearch + ) } override fun loadMore() { diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchResultController.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchResultController.kt index 5b1f17cfe2..4f951dfecb 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchResultController.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchResultController.kt @@ -125,7 +125,7 @@ class SearchResultController @Inject constructor( .formattedDate(dateFormatter.format(event.originServerTs, DateFormatKind.MESSAGE_SIMPLE)) .spannable(spannable.toEpoxyCharSequence()) .sender(eventAndSender.sender - ?: eventAndSender.event.senderId?.let { session.getRoomMember(it, data.roomId) }?.toMatrixItem()) + ?: eventAndSender.event.senderId?.let { session.roomService().getRoomMember(it, data.roomId) }?.toMatrixItem()) .threadDetails(event.threadDetails) .threadSummaryFormatted(displayableEventFormatter.formatThreadSummary(event.threadDetails?.threadSummaryLatestEvent).toString()) .areThreadMessagesEnabled(userPreferencesProvider.areThreadMessagesEnabled()) diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchViewModel.kt index 1702fb95cd..561023401f 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchViewModel.kt @@ -30,11 +30,12 @@ import kotlinx.coroutines.CancellationException import kotlinx.coroutines.Job import kotlinx.coroutines.launch import org.matrix.android.sdk.api.session.Session +import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.search.SearchResult class SearchViewModel @AssistedInject constructor( @Assisted private val initialState: SearchViewState, - session: Session + private val session: Session ) : VectorViewModel(initialState) { private val room = session.getRoom(initialState.roomId) @@ -100,8 +101,9 @@ class SearchViewModel @AssistedInject constructor( currentTask = viewModelScope.launch { try { - val result = room.search( + val result = session.searchService().search( searchTerm = state.searchTerm, + roomId = initialState.roomId, nextBatch = nextBatch, orderByRecent = true, beforeLimit = 0, diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsViewModel.kt index 99c36d1190..df2a1fbe81 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsViewModel.kt @@ -48,6 +48,7 @@ import org.matrix.android.sdk.api.session.events.model.isAttachmentMessage import org.matrix.android.sdk.api.session.events.model.isTextMessage import org.matrix.android.sdk.api.session.events.model.isThread import org.matrix.android.sdk.api.session.events.model.toModel +import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.room.model.message.MessageContent import org.matrix.android.sdk.api.session.room.model.message.MessageFormat import org.matrix.android.sdk.api.session.room.model.message.MessagePollContent @@ -454,7 +455,7 @@ class MessageActionsViewModel @AssistedInject constructor( // if (!vectorPreferences.areThreadMessagesEnabled()) return false // Disable beta prompt if the homeserver do not support threads if (!vectorPreferences.areThreadMessagesEnabled() && - !session.getHomeServerCapabilities().canUseThreading) return false + !session.homeServerCapabilitiesService().getHomeServerCapabilities().canUseThreading) return false if (initialState.isFromThreadTimeline) return false if (event.root.isThread()) return false diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryViewModel.kt index e1d4d71c6a..c8a3bb8967 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryViewModel.kt @@ -32,6 +32,7 @@ import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.crypto.MXCryptoError import org.matrix.android.sdk.api.session.crypto.model.OlmDecryptionResult import org.matrix.android.sdk.api.session.events.model.isReply +import org.matrix.android.sdk.api.session.getRoom import timber.log.Timber import java.util.UUID @@ -61,7 +62,7 @@ class ViewEditHistoryViewModel @AssistedInject constructor( viewModelScope.launch { val data = try { - room.fetchEditHistory(eventId) + room.relationService().fetchEditHistory(eventId) } catch (failure: Throwable) { setState { copy(editList = Fail(failure)) diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/EncryptionItemFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/EncryptionItemFactory.kt index 89899a52e0..0cbd92f525 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/EncryptionItemFactory.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/EncryptionItemFactory.kt @@ -29,6 +29,7 @@ import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.events.model.content.EncryptionEventContent import org.matrix.android.sdk.api.session.events.model.toModel +import org.matrix.android.sdk.api.session.getRoomSummary import javax.inject.Inject class EncryptionItemFactory @Inject constructor( diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/LiveLocationMessageItemFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/LiveLocationMessageItemFactory.kt index 9bc148a562..d233deffb8 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/LiveLocationMessageItemFactory.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/LiveLocationMessageItemFactory.kt @@ -24,7 +24,7 @@ import im.vector.app.features.home.room.detail.timeline.item.AbsMessageItem import im.vector.app.features.home.room.detail.timeline.item.MessageLiveLocationStartItem import im.vector.app.features.home.room.detail.timeline.item.MessageLiveLocationStartItem_ import org.matrix.android.sdk.api.extensions.orFalse -import org.matrix.android.sdk.api.session.room.model.livelocation.LiveLocationBeaconContent +import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconInfoContent import javax.inject.Inject class LiveLocationMessageItemFactory @Inject constructor( @@ -34,19 +34,20 @@ class LiveLocationMessageItemFactory @Inject constructor( ) { fun create( - liveLocationContent: LiveLocationBeaconContent, + beaconInfoContent: MessageBeaconInfoContent, highlight: Boolean, attributes: AbsMessageItem.Attributes, ): VectorEpoxyModel<*>? { // TODO handle location received and stopped states return when { - isLiveRunning(liveLocationContent) -> buildStartLiveItem(highlight, attributes) - else -> null + isLiveRunning(beaconInfoContent) -> buildStartLiveItem(highlight, attributes) + else -> null } } - private fun isLiveRunning(liveLocationContent: LiveLocationBeaconContent): Boolean { - return liveLocationContent.getBestBeaconInfo()?.isLive.orFalse() && liveLocationContent.hasTimedOut.not() + private fun isLiveRunning(beaconInfoContent: MessageBeaconInfoContent): Boolean { + // TODO when we will use aggregatedSummary, check if the live has timed out as well + return beaconInfoContent.isLive.orFalse() } private fun buildStartLiveItem( diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MergedHeaderItemFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MergedHeaderItemFactory.kt index c21b67a459..080a79829a 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MergedHeaderItemFactory.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MergedHeaderItemFactory.kt @@ -38,6 +38,8 @@ import org.matrix.android.sdk.api.query.QueryStringValue import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.content.EncryptionEventContent import org.matrix.android.sdk.api.session.events.model.toModel +import org.matrix.android.sdk.api.session.getRoom +import org.matrix.android.sdk.api.session.room.getStateEvent import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent import org.matrix.android.sdk.api.session.room.model.create.RoomCreateContent import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt index 04e087d25d..e4522b260e 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt @@ -98,8 +98,8 @@ import org.matrix.android.sdk.api.session.events.model.RelationType import org.matrix.android.sdk.api.session.events.model.content.EncryptedEventContent import org.matrix.android.sdk.api.session.events.model.isThread import org.matrix.android.sdk.api.session.events.model.toModel -import org.matrix.android.sdk.api.session.room.model.livelocation.LiveLocationBeaconContent import org.matrix.android.sdk.api.session.room.model.message.MessageAudioContent +import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconInfoContent import org.matrix.android.sdk.api.session.room.model.message.MessageContent import org.matrix.android.sdk.api.session.room.model.message.MessageContentWithFormattedBody import org.matrix.android.sdk.api.session.room.model.message.MessageEmoteContent @@ -207,15 +207,15 @@ class MessageItemFactory @Inject constructor( is MessageAudioContent -> buildAudioContent(params, messageContent, informationData, highlight, attributes) is MessageVerificationRequestContent -> buildVerificationRequestMessageItem(messageContent, informationData, highlight, callback, attributes) is MessagePollContent -> buildPollItem(messageContent, informationData, highlight, callback, attributes) - is MessageLocationContent -> { + is MessageLocationContent -> { if (vectorPreferences.labsRenderLocationsInTimeline()) { buildLocationItem(messageContent, informationData, highlight, attributes) } else { buildMessageTextItem(messageContent.body, false, informationData, highlight, callback, attributes) } } - is LiveLocationBeaconContent -> liveLocationMessageItemFactory.create(messageContent, highlight, attributes) - else -> buildNotHandledMessageItem(messageContent, informationData, highlight, callback, attributes) + is MessageBeaconInfoContent -> liveLocationMessageItemFactory.create(messageContent, highlight, attributes) + else -> buildNotHandledMessageItem(messageContent, informationData, highlight, callback, attributes) } return messageItem?.apply { layout(informationData.messageLayout.layoutRes) @@ -436,7 +436,7 @@ class MessageItemFactory @Inject constructor( val otherUserId = if (informationData.sentByMe) messageContent.toUserId else informationData.senderId val otherUserName = if (informationData.sentByMe) { - session.getRoomMember(messageContent.toUserId, roomId)?.displayName + session.roomService().getRoomMember(messageContent.toUserId, roomId)?.displayName } else { informationData.memberName } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/TimelineFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/TimelineFactory.kt index 3ec1366131..5d2f69eee4 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/TimelineFactory.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/TimelineFactory.kt @@ -22,6 +22,7 @@ import im.vector.app.features.home.room.detail.timeline.merged.MergedTimelines import kotlinx.coroutines.CoroutineScope import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.events.model.EventType +import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.room.Room import org.matrix.android.sdk.api.session.room.timeline.Timeline import javax.inject.Inject @@ -44,18 +45,18 @@ class TimelineFactory @Inject constructor(private val session: Session, private val settings = timelineSettingsFactory.create(rootThreadEventId) if (!session.vectorCallService.protocolChecker.supportVirtualRooms) { - return mainRoom.createTimeline(eventId, settings) + return mainRoom.timelineService().createTimeline(eventId, settings) } val virtualRoomId = session.vectorCallService.userMapper.virtualRoomForNativeRoom(mainRoom.roomId) return if (virtualRoomId == null) { - mainRoom.createTimeline(eventId, settings) + mainRoom.timelineService().createTimeline(eventId, settings) } else { val virtualRoom = session.getRoom(virtualRoomId)!! MergedTimelines( coroutineScope = coroutineScope, - mainTimeline = mainRoom.createTimeline(eventId, settings), + mainTimeline = mainRoom.timelineService().createTimeline(eventId, settings), secondaryTimelineParams = MergedTimelines.SecondaryTimelineParams( - timeline = virtualRoom.createTimeline(null, settings), + timeline = virtualRoom.timelineService().createTimeline(null, settings), shouldFilterTypes = true, allowedTypes = secondaryTimelineAllowedTypes ) diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/VerificationItemFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/VerificationItemFactory.kt index fb8f8fce9d..ecd80297fc 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/VerificationItemFactory.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/VerificationItemFactory.kt @@ -32,6 +32,8 @@ import org.matrix.android.sdk.api.session.crypto.verification.safeValueOf import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.RelationType import org.matrix.android.sdk.api.session.events.model.toModel +import org.matrix.android.sdk.api.session.getRoom +import org.matrix.android.sdk.api.session.room.getTimelineEvent import org.matrix.android.sdk.api.session.room.model.message.MessageRelationContent import org.matrix.android.sdk.api.session.room.model.message.MessageVerificationCancelContent import javax.inject.Inject diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/LocationPinProvider.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/LocationPinProvider.kt index 7262284c95..8ef910c931 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/LocationPinProvider.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/LocationPinProvider.kt @@ -29,6 +29,7 @@ import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.glide.GlideApp import im.vector.app.core.utils.DimensionConverter import im.vector.app.features.home.AvatarRenderer +import org.matrix.android.sdk.api.session.getUser import org.matrix.android.sdk.api.util.toMatrixItem import timber.log.Timber import javax.inject.Inject diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/reactions/ViewReactionsViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/reactions/ViewReactionsViewModel.kt index 29b8c207df..deb22bbe04 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/reactions/ViewReactionsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/reactions/ViewReactionsViewModel.kt @@ -33,6 +33,8 @@ import im.vector.app.core.platform.VectorViewModel import im.vector.app.features.home.room.detail.timeline.action.TimelineEventFragmentArgs import kotlinx.coroutines.flow.map import org.matrix.android.sdk.api.session.Session +import org.matrix.android.sdk.api.session.getRoom +import org.matrix.android.sdk.api.session.room.getTimelineEvent import org.matrix.android.sdk.flow.flow import org.matrix.android.sdk.flow.unwrap diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/render/EventTextRenderer.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/render/EventTextRenderer.kt index d50a6fb297..83cffc4279 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/render/EventTextRenderer.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/render/EventTextRenderer.kt @@ -62,7 +62,7 @@ class EventTextRenderer @AssistedInject constructor(@Assisted private val roomId * ========================================================================================== */ private fun addNotifyEveryoneSpans(text: Spannable, roomId: String) { - val room: RoomSummary? = sessionHolder.getSafeActiveSession()?.getRoomSummary(roomId) + val room: RoomSummary? = sessionHolder.getSafeActiveSession()?.roomService()?.getRoomSummary(roomId) val matrixItem = MatrixItem.EveryoneInRoomItem( id = roomId, avatarUrl = room?.avatarUrl, diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/style/TimelineMessageLayoutFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/style/TimelineMessageLayoutFactory.kt index f2334e5a4f..ff3fd7b637 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/style/TimelineMessageLayoutFactory.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/style/TimelineMessageLayoutFactory.kt @@ -59,12 +59,12 @@ class TimelineMessageLayoutFactory @Inject constructor(private val session: Sess MessageType.MSGTYPE_VIDEO, MessageType.MSGTYPE_STICKER_LOCAL, MessageType.MSGTYPE_EMOTE, - MessageType.MSGTYPE_LIVE_LOCATION_STATE, + MessageType.MSGTYPE_BEACON_INFO, ) private val MSG_TYPES_WITH_TIMESTAMP_INSIDE_MESSAGE = setOf( MessageType.MSGTYPE_IMAGE, MessageType.MSGTYPE_VIDEO, - MessageType.MSGTYPE_LIVE_LOCATION_STATE, + MessageType.MSGTYPE_BEACON_INFO, ) } @@ -151,8 +151,8 @@ class TimelineMessageLayoutFactory @Inject constructor(private val session: Sess private fun MessageContent?.shouldAddMessageOverlay(): Boolean { return when { - this == null || msgType == MessageType.MSGTYPE_LIVE_LOCATION_STATE -> false - msgType == MessageType.MSGTYPE_LOCATION -> vectorPreferences.labsRenderLocationsInTimeline() + this == null || msgType == MessageType.MSGTYPE_BEACON_INFO -> false + msgType == MessageType.MSGTYPE_LOCATION -> vectorPreferences.labsRenderLocationsInTimeline() else -> msgType in MSG_TYPES_WITH_TIMESTAMP_INSIDE_MESSAGE } } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/MigrateRoomViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/MigrateRoomViewModel.kt index 5a535e5696..0e4aebecfc 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/MigrateRoomViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/MigrateRoomViewModel.kt @@ -29,6 +29,8 @@ import im.vector.app.core.platform.VectorViewModel import im.vector.app.features.session.coroutineScope import kotlinx.coroutines.launch import org.matrix.android.sdk.api.session.Session +import org.matrix.android.sdk.api.session.getRoom +import org.matrix.android.sdk.api.session.getRoomSummary class MigrateRoomViewModel @AssistedInject constructor( @Assisted initialState: MigrateRoomViewState, @@ -41,7 +43,7 @@ class MigrateRoomViewModel @AssistedInject constructor( val summary = session.getRoomSummary(initialState.roomId) setState { copy( - currentVersion = room?.getRoomVersion(), + currentVersion = room?.roomVersionService()?.getRoomVersion(), isPublic = summary?.isPublic ?: false, otherMemberCount = summary?.otherMemberIds?.count() ?: 0, knownParents = summary?.flattenParentIds ?: emptyList() diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/UpgradeRoomViewModelTask.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/UpgradeRoomViewModelTask.kt index 8859aaeacf..2f91b9a35a 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/UpgradeRoomViewModelTask.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/UpgradeRoomViewModelTask.kt @@ -20,6 +20,7 @@ import im.vector.app.core.platform.ViewModelTask import im.vector.app.core.resources.StringProvider import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.session.Session +import org.matrix.android.sdk.api.session.getRoom import timber.log.Timber import javax.inject.Inject @@ -49,12 +50,12 @@ class UpgradeRoomViewModelTask @Inject constructor( val room = session.getRoom(params.roomId) ?: return Result.UnknownRoom - if (!room.userMayUpgradeRoom(session.myUserId)) { + if (!room.roomVersionService().userMayUpgradeRoom(session.myUserId)) { return Result.NotAllowed } val updatedRoomId = try { - room.upgradeToVersion(params.newVersion) + room.roomVersionService().upgradeToVersion(params.newVersion) } catch (failure: Throwable) { return Result.ErrorFailure(failure) } @@ -64,7 +65,7 @@ class UpgradeRoomViewModelTask @Inject constructor( params.userIdsToAutoInvite.forEach { params.progressReporter?.invoke(false, currentStep, totalStep) tryOrNull { - session.getRoom(updatedRoomId)?.invite(it) + session.getRoom(updatedRoomId)?.membershipService()?.invite(it) } currentStep++ } diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt index aaa469f68d..426ceb5024 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt @@ -44,12 +44,14 @@ import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.resources.UserPreferencesProvider import im.vector.app.databinding.FragmentRoomListBinding import im.vector.app.features.analytics.plan.MobileScreen +import im.vector.app.features.analytics.plan.ViewRoom import im.vector.app.features.home.RoomListDisplayMode import im.vector.app.features.home.room.filtered.FilteredRoomFooterItem import im.vector.app.features.home.room.list.actions.RoomListQuickActionsBottomSheet import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedAction import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedActionViewModel import im.vector.app.features.home.room.list.widget.NotifsFabMenuView +import im.vector.app.features.matrixto.OriginOfMatrixTo import im.vector.app.features.notifications.NotificationDrawerManager import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.launchIn @@ -179,7 +181,7 @@ class RoomListFragment @Inject constructor( } private fun handleShowMxToLink(link: String) { - navigator.openMatrixToBottomSheet(requireContext(), link) + navigator.openMatrixToBottomSheet(requireContext(), link, OriginOfMatrixTo.ROOM_LIST) } override fun onDestroyView() { @@ -196,7 +198,12 @@ class RoomListFragment @Inject constructor( } private fun handleSelectRoom(event: RoomListViewEvents.SelectRoom, isInviteAlreadyAccepted: Boolean) { - navigator.openRoom(context = requireActivity(), roomId = event.roomSummary.roomId, isInviteAlreadyAccepted = isInviteAlreadyAccepted) + navigator.openRoom( + context = requireActivity(), + roomId = event.roomSummary.roomId, + isInviteAlreadyAccepted = isInviteAlreadyAccepted, + trigger = ViewRoom.Trigger.RoomList + ) } private fun setupCreateRoomButton() { diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderGroup.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderGroup.kt index bd43a83f2c..0a31987ae5 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderGroup.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderGroup.kt @@ -70,11 +70,11 @@ class RoomListSectionBuilderGroup( }, { qpm -> val name = stringProvider.getString(R.string.bottom_action_rooms) - val updatableFilterLivePageResult = session.getFilteredPagedRoomSummariesLive(qpm) + val updatableFilterLivePageResult = session.roomService().getFilteredPagedRoomSummariesLive(qpm) onUpdatable(updatableFilterLivePageResult) val itemCountFlow = updatableFilterLivePageResult.livePagedList.asFlow() - .flatMapLatest { session.getRoomCountLive(updatableFilterLivePageResult.queryParams).asFlow() } + .flatMapLatest { session.roomService().getRoomCountLive(updatableFilterLivePageResult.queryParams).asFlow() } .distinctUntilChanged() sections.add( @@ -252,7 +252,7 @@ class RoomListSectionBuilderGroup( query: (RoomSummaryQueryParams.Builder) -> Unit) { withQueryParams(query) { roomQueryParams -> val name = stringProvider.getString(nameRes) - session.getFilteredPagedRoomSummariesLive(roomQueryParams) + session.roomService().getFilteredPagedRoomSummariesLive(roomQueryParams) .also { activeSpaceUpdaters.add(it) }.livePagedList @@ -262,7 +262,7 @@ class RoomListSectionBuilderGroup( .onEach { sections.find { it.sectionName == name } ?.notificationCount - ?.postValue(session.getNotificationCountForRooms(roomQueryParams)) + ?.postValue(session.roomService().getNotificationCountForRooms(roomQueryParams)) } .flowOn(Dispatchers.Default) .launchIn(coroutineScope) @@ -272,7 +272,7 @@ class RoomListSectionBuilderGroup( sectionName = name, livePages = livePagedList, notifyOfLocalEcho = notifyOfLocalEcho, - itemCount = session.getRoomCountLive(roomQueryParams).asFlow() + itemCount = session.roomService().getRoomCountLive(roomQueryParams).asFlow() ) ) } diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderSpace.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderSpace.kt index d405bc5b6f..59137ec490 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderSpace.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderSpace.kt @@ -47,6 +47,7 @@ import org.matrix.android.sdk.api.query.ActiveSpaceFilter import org.matrix.android.sdk.api.query.RoomCategoryFilter import org.matrix.android.sdk.api.query.RoomTagQueryFilter import org.matrix.android.sdk.api.session.Session +import org.matrix.android.sdk.api.session.getRoomSummary import org.matrix.android.sdk.api.session.room.RoomSummaryQueryParams import org.matrix.android.sdk.api.session.room.UpdatableLivePageResult import org.matrix.android.sdk.api.session.room.model.Membership @@ -324,11 +325,11 @@ class RoomListSectionBuilderSpace( }, { qpm -> val name = stringProvider.getString(R.string.bottom_action_rooms) - val updatableFilterLivePageResult = session.getFilteredPagedRoomSummariesLive(qpm) + val updatableFilterLivePageResult = session.roomService().getFilteredPagedRoomSummariesLive(qpm) onUpdatable(updatableFilterLivePageResult) val itemCountFlow = updatableFilterLivePageResult.livePagedList.asFlow() - .flatMapLatest { session.getRoomCountLive(updatableFilterLivePageResult.queryParams).asFlow() } + .flatMapLatest { session.roomService().getRoomCountLive(updatableFilterLivePageResult.queryParams).asFlow() } .distinctUntilChanged() sections.add( @@ -354,13 +355,13 @@ class RoomListSectionBuilderSpace( val liveQueryParams = MutableStateFlow(updatedQueryParams) val itemCountFlow = liveQueryParams .flatMapLatest { - session.getRoomCountLive(it).asFlow() + session.roomService().getRoomCountLive(it).asFlow() } .flowOn(Dispatchers.Main) .distinctUntilChanged() val name = stringProvider.getString(nameRes) - val filteredPagedRoomSummariesLive = session.getFilteredPagedRoomSummariesLive( + val filteredPagedRoomSummariesLive = session.roomService().getFilteredPagedRoomSummariesLive( roomQueryParams.process(spaceFilterStrategy, appStateHandler.safeActiveSpaceId()), pagedListConfig ) @@ -407,7 +408,7 @@ class RoomListSectionBuilderSpace( if (countRoomAsNotif) { RoomAggregateNotificationCount(it.size, it.size) } else { - session.getNotificationCountForRooms( + session.roomService().getNotificationCountForRooms( roomQueryParams.process(spaceFilterStrategy, appStateHandler.safeActiveSpaceId()) ) } diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt index 70974bc1f6..9fd6de1a74 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt @@ -32,6 +32,8 @@ import im.vector.app.core.di.hiltMavericksViewModelFactory import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.resources.StringProvider import im.vector.app.features.analytics.AnalyticsTracker +import im.vector.app.features.analytics.extensions.toAnalyticsJoinedRoom +import im.vector.app.features.analytics.plan.JoinedRoom import im.vector.app.features.displayname.getBestName import im.vector.app.features.invite.AutoAcceptInvites import im.vector.app.features.settings.VectorPreferences @@ -42,6 +44,8 @@ import kotlinx.coroutines.launch import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.query.QueryStringValue import org.matrix.android.sdk.api.session.Session +import org.matrix.android.sdk.api.session.getRoom +import org.matrix.android.sdk.api.session.getRoomSummary import org.matrix.android.sdk.api.session.room.UpdatableLivePageResult import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState import org.matrix.android.sdk.api.session.room.model.tag.RoomTag @@ -166,7 +170,7 @@ class RoomListViewModel @AssistedInject constructor( } fun isPublicRoom(roomId: String): Boolean { - return session.getRoom(roomId)?.isPublic().orFalse() + return session.getRoom(roomId)?.stateService()?.isPublic().orFalse() } // PRIVATE METHODS ***************************************************************************** @@ -233,7 +237,7 @@ class RoomListViewModel @AssistedInject constructor( viewModelScope.launch { try { - session.leaveRoom(roomId) + session.roomService().leaveRoom(roomId) // We do not update the rejectingRoomsIds here, because, the room is not rejected yet regarding the sync data. // Instead, we wait for the room to be rejected // Known bug: if the user is invited again (after rejecting the first invitation), the loading will be displayed instead of the buttons. @@ -250,7 +254,7 @@ class RoomListViewModel @AssistedInject constructor( if (room != null) { viewModelScope.launch { try { - room.setRoomNotificationState(action.notificationState) + room.roomPushRuleService().setRoomNotificationState(action.notificationState) } catch (failure: Exception) { _viewEvents.post(RoomListViewEvents.Failure(failure)) } @@ -265,7 +269,7 @@ class RoomListViewModel @AssistedInject constructor( viewModelScope.launch { try { - session.joinRoom(action.roomId, null, action.viaServers ?: emptyList()) + session.roomService().joinRoom(action.roomId, null, action.viaServers ?: emptyList()) suggestedRoomJoiningState.postValue(suggestedRoomJoiningState.value.orEmpty().toMutableMap().apply { this[action.roomId] = Success(Unit) @@ -275,6 +279,8 @@ class RoomListViewModel @AssistedInject constructor( this[action.roomId] = Fail(failure) }.toMap()) } + session.getRoomSummary(action.roomId) + ?.let { analyticsTracker.capture(it.toAnalyticsJoinedRoom(JoinedRoom.Trigger.RoomDirectory)) } } } @@ -293,13 +299,13 @@ class RoomListViewModel @AssistedInject constructor( action.tag.otherTag() ?.takeIf { room.roomSummary()?.hasTag(it).orFalse() } ?.let { tagToRemove -> - room.deleteTag(tagToRemove) + room.tagsService().deleteTag(tagToRemove) } // Set the tag. We do not handle the order for the moment - room.addTag(action.tag, 0.5) + room.tagsService().addTag(action.tag, 0.5) } else { - room.deleteTag(action.tag) + room.tagsService().deleteTag(action.tag) } } catch (failure: Throwable) { _viewEvents.post(RoomListViewEvents.Failure(failure)) @@ -319,7 +325,7 @@ class RoomListViewModel @AssistedInject constructor( private fun handleLeaveRoom(action: RoomListAction.LeaveRoom) { _viewEvents.post(RoomListViewEvents.Loading(null)) viewModelScope.launch { - val value = runCatching { session.leaveRoom(action.roomId) } + val value = runCatching { session.roomService().leaveRoom(action.roomId) } .fold({ RoomListViewEvents.Done }, { RoomListViewEvents.Failure(it) }) _viewEvents.post(value) } diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/SpaceChildInfoItem.kt b/vector/src/main/java/im/vector/app/features/home/room/list/SpaceChildInfoItem.kt index 99cbd45294..a2cb905f1b 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/SpaceChildInfoItem.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/SpaceChildInfoItem.kt @@ -40,7 +40,7 @@ import me.gujun.android.span.image import me.gujun.android.span.span import org.matrix.android.sdk.api.util.MatrixItem -@EpoxyModelClass(layout = R.layout.item_suggested_room) +@EpoxyModelClass(layout = R.layout.item_explore_space_child) abstract class SpaceChildInfoItem : VectorEpoxyModel() { @EpoxyAttribute lateinit var avatarRenderer: AvatarRenderer @@ -51,6 +51,7 @@ abstract class SpaceChildInfoItem : VectorEpoxyModel( @EpoxyAttribute var memberCount: Int = 0 @EpoxyAttribute var loading: Boolean = false + @EpoxyAttribute var suggested: Boolean = false @EpoxyAttribute var buttonLabel: String? = null @EpoxyAttribute var errorLabel: String? = null @@ -89,6 +90,7 @@ abstract class SpaceChildInfoItem : VectorEpoxyModel( } } + holder.suggestedTag.visibility = if (suggested) View.VISIBLE else View.GONE holder.joinButton.text = buttonLabel if (loading) { @@ -121,7 +123,8 @@ abstract class SpaceChildInfoItem : VectorEpoxyModel( val titleView by bind(R.id.roomNameView) val joinButton by bind