diff --git a/.editorconfig b/.editorconfig
index 4640e50d15..4f23d46afd 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -764,13 +764,13 @@ ij_groovy_while_on_new_line = false
ij_groovy_wrap_long_lines = false
[{*.gradle.kts,*.kt,*.kts,*.main.kts}]
-ij_kotlin_align_in_columns_case_branch = true
+ij_kotlin_align_in_columns_case_branch = false
ij_kotlin_align_multiline_binary_operation = false
ij_kotlin_align_multiline_extends_list = false
ij_kotlin_align_multiline_method_parentheses = false
ij_kotlin_align_multiline_parameters = true
ij_kotlin_align_multiline_parameters_in_calls = false
-ij_kotlin_allow_trailing_comma = false
+ij_kotlin_allow_trailing_comma = true
ij_kotlin_allow_trailing_comma_on_call_site = false
ij_kotlin_assignment_wrap = off
ij_kotlin_blank_lines_after_class_header = 0
diff --git a/.github/ISSUE_TEMPLATE/release.yml b/.github/ISSUE_TEMPLATE/release.yml
index 7cb47fa952..b063c93530 100644
--- a/.github/ISSUE_TEMPLATE/release.yml
+++ b/.github/ISSUE_TEMPLATE/release.yml
@@ -29,7 +29,7 @@ body:
- [ ] Check the rageshake with the current dev version: https://github.com/matrix-org/element-android-rageshakes/labels/1.2.3-dev
- [ ] Run the integration test, and especially `UiAllScreensSanityTest.allScreensTest()`
- [ ] Create an account on matrix.org and do some smoke tests that the sanity test does not cover like: 1-1 call, 1-1 video call, Jitsi call for instance
- - [ ] Run towncrier: `towncrier --version v1.2.3 --draft` (remove `--draft` do write the file CHANGES.md)
+ - [ ] Run towncrier: `towncrier build --version v1.2.3 --draft` (remove `--draft` do write the file CHANGES.md)
- [ ] Check that the folder `changelog.d` is empty. It can happen that some remaining files stay here
- [ ] Check the file CHANGES.md consistency. It's possible to reorder items (most important changes first) or change their section if relevant. Also an opportunity to fix some typo, or rewrite things
- [ ] Add file for fastlane under ./fastlane/metadata/android/en-US/changelogs
@@ -49,24 +49,34 @@ body:
### Once tested and validated internally
- - [ ] Create a new beta release on the GooglePlay console and upload the 4 signed Apks.
+ - [ ] Create a new open testing release on the GooglePlay console and upload the 4 signed Apks.
- [ ] Check that the version codes are correct
- [ ] Copy the fastlane change to the GooglePlay console in the section en-GB.
- - [ ] Push to beta release to 100% of the users
- - [ ] Notify the F-Droid team so that they can schedule the publication on F-Droid
+ - [ ] Push the open testing release to 100% of the users
+ - [ ] Notify the F-Droid team [here](https://matrix.to/#/!LAAuJLQXYHjMNWKrCK:matrix.org?via=matrix.org&via=bubu1.eu&via=lant.uk) so that they can schedule the publication on F-Droid
+ - [ ] The application is available to the PlayStore testers (live). Google can take between 1 hour and up to 7 days to approve the release.
+ - [ ] The application is available to the F-Droid users.
- ### Once Live on PlayStore
+ ### Once open testing is live on PlayStore
- [ ] Ping the Android public room and update its topic
- - [ ] Add an entry in the internal diary
- ### After at least 2 days
+ ### Once Live on F-Droid
+
+ - [ ] Update the Android public room topic
+
+ ### After at least 2 days (generally next Monday)
- [ ] Check the [rageshakes](https://github.com/matrix-org/element-android-rageshakes/issues)
- [ ] Check the crash reports on the GooglePlay console
- [ ] Check the Android Element room for any reported issues on the new version
- - [ ] If all is OK, push to production and notify Markus (Bubu) to release the F-Droid version
- - [ ] Ping the Android public room and update its topic with the new available version
+ - [ ] If all is OK, promote the open testing release to production. Generally using a 100% roll out, but can be a smaller value depending on the release content.
+ - [ ] The application is available to the PlayStore users (live). Google can take (again!) between 1 hour and up to 7 days to approve the release.
+
+ ### Once production is live on PlayStore
+
+ - [ ] Ping the Android public room and update its topic
+ - [ ] Add an entry in the internal diary
### Android SDK2
@@ -90,12 +100,20 @@ body:
##### Release on MavenCentral
+ - [ ] Checkout the branch `main`
- [ ] Run the command `./gradlew publish --no-daemon --no-parallel`. You'll need some non-public element to do so
+ - [ ] Run the command `./gradlew closeAndReleaseRepository`. If it is working well, you can jump directly to the final step of this section.
+
+ If `./gradlew closeAndReleaseRepository` fails (for instance, several repositories are waiting to be handled), you have to close and release the repository manually. Do the following steps:
+
- [ ] Connect to https://s01.oss.sonatype.org
- [ ] Click on Staging Repositories and check the the files have been uploaded
- [ ] Click on close
- [ ] Wait (check Activity tab until step "Repository closed" is displayed)
- [ ] Click on release. The staging repository will disappear
+
+ Final step
+
- [ ] Check that the release is available in https://repo1.maven.org/maven2/org/matrix/android/matrix-android-sdk2/ (it can take a few minutes)
##### Release on GitHub
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 9517a4f3a7..933c442501 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -7,9 +7,8 @@ on:
# Enrich gradle.properties for CI/CD
env:
- CI_GRADLE_ARG_PROPERTIES: >
- -Porg.gradle.jvmargs=-Xmx2g
- -Porg.gradle.parallel=false
+ GRADLE_OPTS: -Dorg.gradle.jvmargs="-Xmx3072m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError" -Dkotlin.daemon.jvm.options="-Xmx2560m" -Dkotlin.incremental=false
+ CI_GRADLE_ARG_PROPERTIES: --stacktrace -PpreDexEnable=false --max-workers 2 --no-daemon
jobs:
debug:
@@ -35,7 +34,7 @@ jobs:
restore-keys: |
${{ runner.os }}-gradle-
- name: Assemble ${{ matrix.target }} debug apk
- run: ./gradlew assemble${{ matrix.target }}Debug $CI_GRADLE_ARG_PROPERTIES --stacktrace
+ run: ./gradlew assemble${{ matrix.target }}Debug $CI_GRADLE_ARG_PROPERTIES
- name: Upload ${{ matrix.target }} debug APKs
uses: actions/upload-artifact@v3
with:
@@ -46,8 +45,9 @@ jobs:
release:
name: Build unsigned GPlay APKs
runs-on: ubuntu-latest
- if: github.ref == 'refs/heads/main'
- # Only runs on main, no concurrency.
+ concurrency:
+ group: ${{ github.ref == 'refs/head/main' && format('build-release-apk-main-{0}', github.sha) || github.ref == 'refs/heads/develop' && format('build-release-apk-develop-{0}', github.sha) || format('build-debug-{0}', github.ref) }}
+ cancel-in-progress: ${{ github.ref != 'refs/head/main' }}
steps:
- uses: actions/checkout@v3
- uses: actions/cache@v3
@@ -59,7 +59,7 @@ jobs:
restore-keys: |
${{ runner.os }}-gradle-
- name: Assemble GPlay unsigned apk
- run: ./gradlew clean assembleGplayRelease $CI_GRADLE_ARG_PROPERTIES --stacktrace
+ run: ./gradlew clean assembleGplayRelease $CI_GRADLE_ARG_PROPERTIES
- name: Upload Gplay unsigned APKs
uses: actions/upload-artifact@v3
with:
@@ -67,4 +67,26 @@ jobs:
path: |
vector/build/outputs/apk/*/release/*.apk
-# TODO add exodus checks
+ exodus:
+ runs-on: ubuntu-latest
+ needs: release
+ steps:
+ - name: Obtain apk from artifact
+ id: download
+ uses: actions/download-artifact@v3
+ with:
+ name: vector-gplay-release-unsigned
+ - name: Show apks in artifact
+ run: ls -R ${{steps.download.outputs.download-path}}
+ - name: Execute exodus-standalone
+ uses: docker://exodusprivacy/exodus-standalone:latest
+ with:
+ args: /github/workspace/gplay/release/vector-gplay-universal-release-unsigned.apk -j -o /github/workspace/exodus.json
+ - name: Upload exodus json report
+ uses: actions/upload-artifact@v3
+ with:
+ name: exodus.json
+ path: |
+ exodus.json
+ - name: Check for trackers
+ run: "jq -e '.trackers == []' exodus.json > /dev/null || { echo '::error static analysis identified user tracking library' ; exit 1; }"
diff --git a/.github/workflows/danger.yml b/.github/workflows/danger.yml
new file mode 100644
index 0000000000..d36f2d0765
--- /dev/null
+++ b/.github/workflows/danger.yml
@@ -0,0 +1,20 @@
+name: Danger CI
+
+on: [pull_request]
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ name: Danger
+ steps:
+ - uses: actions/checkout@v3
+ - run: |
+ npm install --save-dev @babel/plugin-transform-flow-strip-types
+ - name: Danger
+ uses: danger/danger-js@11.1.1
+ with:
+ args: "--dangerfile tools/danger/dangerfile.js"
+ env:
+ DANGER_GITHUB_API_TOKEN: ${{ secrets.DANGER_GITHUB_API_TOKEN }}
+ # Fallback for forks
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/gradle-wrapper-validation.yml b/.github/workflows/gradle-wrapper-validation.yml
index 4e701faa44..7b68c0077d 100644
--- a/.github/workflows/gradle-wrapper-validation.yml
+++ b/.github/workflows/gradle-wrapper-validation.yml
@@ -1,5 +1,8 @@
name: "Validate Gradle Wrapper"
-on: [push, pull_request]
+on:
+ pull_request: { }
+ push:
+ branches: [ main, develop ]
jobs:
validation:
diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml
new file mode 100644
index 0000000000..51c1b32e82
--- /dev/null
+++ b/.github/workflows/nightly.yml
@@ -0,0 +1,46 @@
+name: Build and release nightly APK
+
+on:
+ schedule:
+ # Every nights at 4
+ - cron: "0 4 * * *"
+
+env:
+ GRADLE_OPTS: -Dorg.gradle.jvmargs="-Xmx3072m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError" -Dkotlin.daemon.jvm.options="-Xmx2560m" -Dkotlin.incremental=false
+ CI_GRADLE_ARG_PROPERTIES: --stacktrace -PpreDexEnable=false --max-workers 2 --no-daemon
+
+jobs:
+ nightly:
+ name: Build and publish nightly Gplay APK to Firebase
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ - name: Set up Python 3.8
+ uses: actions/setup-python@v4
+ with:
+ python-version: 3.8
+ - uses: actions/cache@v3
+ with:
+ path: |
+ ~/.gradle/caches
+ ~/.gradle/wrapper
+ key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
+ restore-keys: |
+ ${{ runner.os }}-gradle-
+ - name: Install towncrier
+ run: |
+ python3 -m pip install towncrier
+ - name: Prepare changelog file
+ run: |
+ mv towncrier.toml towncrier.toml.bak
+ sed 's/CHANGES\.md/CHANGES_NIGHTLY\.md/' towncrier.toml.bak > towncrier.toml
+ rm towncrier.toml.bak
+ yes n | towncrier build --version nightly
+ - name: Build and upload Gplay Nightly APK
+ run: |
+ ./gradlew assembleGplayNightly appDistributionUploadGplayNightly $CI_GRADLE_ARG_PROPERTIES
+ env:
+ ELEMENT_ANDROID_NIGHTLY_KEYID: ${{ secrets.ELEMENT_ANDROID_NIGHTLY_KEYID }}
+ ELEMENT_ANDROID_NIGHTLY_KEYPASSWORD: ${{ secrets.ELEMENT_ANDROID_NIGHTLY_KEYPASSWORD }}
+ ELEMENT_ANDROID_NIGHTLY_STOREPASSWORD: ${{ secrets.ELEMENT_ANDROID_NIGHTLY_STOREPASSWORD }}
+ FIREBASE_TOKEN: ${{ secrets.ELEMENT_ANDROID_NIGHTLY_FIREBASE_TOKEN }}
diff --git a/.github/workflows/post-pr.yml b/.github/workflows/post-pr.yml
index 49669e4201..5cde95e625 100644
--- a/.github/workflows/post-pr.yml
+++ b/.github/workflows/post-pr.yml
@@ -10,9 +10,8 @@ on:
# Enrich gradle.properties for CI/CD
env:
- CI_GRADLE_ARG_PROPERTIES: >
- -Porg.gradle.jvmargs=-Xmx4g
- -Porg.gradle.parallel=false
+ GRADLE_OPTS: -Dorg.gradle.jvmargs="-Xmx3072m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError" -Dkotlin.daemon.jvm.options="-Xmx2560m" -Dkotlin.incremental=false
+ CI_GRADLE_ARG_PROPERTIES: --stacktrace -PpreDexEnable=false --max-workers 2 --no-daemon
jobs:
@@ -41,7 +40,7 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Set up Python 3.8
- uses: actions/setup-python@v3
+ uses: actions/setup-python@v4
with:
python-version: 3.8
- uses: actions/cache@v3
diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml
index 014139d0ba..544d9081f8 100644
--- a/.github/workflows/quality.yml
+++ b/.github/workflows/quality.yml
@@ -7,8 +7,8 @@ on:
# Enrich gradle.properties for CI/CD
env:
- CI_GRADLE_ARG_PROPERTIES: >
- -Porg.gradle.jvmargs=-Xmx4g
+ GRADLE_OPTS: -Dorg.gradle.jvmargs="-Xmx3072m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError" -Dkotlin.daemon.jvm.options="-Xmx2560m" -Dkotlin.incremental=false
+ CI_GRADLE_ARG_PROPERTIES: --stacktrace -PpreDexEnable=false --max-workers 2 --no-daemon
jobs:
check:
@@ -19,7 +19,7 @@ jobs:
- name: Run code quality check suite
run: ./tools/check/check_code_quality.sh
-# Knit for all the modules (https://github.com/Kotlin/kotlinx-knit)
+ # Knit for all the modules (https://github.com/Kotlin/kotlinx-knit)
knit:
name: Knit
runs-on: ubuntu-latest
@@ -27,82 +27,54 @@ jobs:
- uses: actions/checkout@v3
- name: Run knit
run: |
- ./gradlew knit
+ ./gradlew knitCheck
-# ktlint for all the modules
- ktlint:
- name: Kotlin Linter
+ # Check the project: ktlint, detekt, lint
+ lint:
+ name: Android Linter
runs-on: ubuntu-latest
# Allow all jobs on main and develop. Just one per PR.
concurrency:
- group: ${{ github.ref == 'refs/heads/main' && format('ktlint-main-{0}', github.sha) || github.ref == 'refs/heads/develop' && format('ktlint-develop-{0}', github.sha) || format('ktlint-{0}', github.ref) }}
+ group: ${{ github.ref == 'refs/heads/main' && format('lint-main-{0}', github.sha) || github.ref == 'refs/heads/develop' && format('lint-develop-{0}', github.sha) || format('lint-{0}', github.ref) }}
cancel-in-progress: true
steps:
- uses: actions/checkout@v3
- name: Run ktlint
run: |
./gradlew ktlintCheck --continue
+ - name: Run detekt
+ if: always()
+ run: |
+ ./gradlew detekt $CI_GRADLE_ARG_PROPERTIES
+ - name: Run lint
+ # Not always, if ktlint or detekt fail, avoid running the long lint check.
+ run: |
+ ./gradlew lintGplayRelease $CI_GRADLE_ARG_PROPERTIES
+ ./gradlew lintFdroidRelease $CI_GRADLE_ARG_PROPERTIES
- name: Upload reports
if: always()
uses: actions/upload-artifact@v3
with:
- name: ktlinting-report
+ name: linting-report
path: |
- */build/reports/ktlint/ktlint*/ktlint*.txt
- - name: Handle Results
+ */build/reports/**/*.*
+ - name: Prepare Danger
if: always()
- id: ktlint-results
run: |
- results="$(cat */*/build/reports/ktlint/ktlint*/ktlint*.txt */build/reports/ktlint/ktlint*/ktlint*.txt | sed -r "s/\x1B\[([0-9]{1,3}(;[0-9]{1,2})?)?[mGK]//g")"
- if [ -z "$results" ]; then
- echo "::set-output name=add_comment::false"
- else
- body="👎\`Failed${results}\`"
- body="${body//'%'/'%25'}"
- body="${body//$'\n'/'%0A'}"
- body="${body//$'\r'/'%0D'}"
- body="$( echo $body | sed 's/\/home\/runner\/work\/element-android\/element-android\//\`
\`/g')"
- body="$( echo $body | sed 's/\/src\/main\/java\// 🔸 /g')"
- body="$( echo $body | sed 's/im\/vector\/app\///g')"
- body="$( echo $body | sed 's/im\/vector\/lib\/attachmentviewer\///g')"
- body="$( echo $body | sed 's/im\/vector\/lib\/multipicker\///g')"
- body="$( echo $body | sed 's/im\/vector\/lib\///g')"
- body="$( echo $body | sed 's/org\/matrix\/android\/sdk\///g')"
- body="$( echo $body | sed 's/\/src\/androidTest\/java\// 🔸 /g')"
- echo "::set-output name=add_comment::true"
- echo "::set-output name=body::$body"
- fi
- - name: Find Comment
- if: always() && github.event_name == 'pull_request'
- uses: peter-evans/find-comment@v2
- id: fc
+ npm install --save-dev @babel/core
+ npm install --save-dev @babel/plugin-transform-flow-strip-types
+ yarn add danger-plugin-lint-report --dev
+ - name: Danger lint
+ if: always()
+ uses: danger/danger-js@11.1.1
with:
- issue-number: ${{ github.event.pull_request.number }}
- comment-author: 'github-actions[bot]'
- body-includes: Ktlint Results
- - name: Add comment if needed
- if: always() && github.event_name == 'pull_request' && steps.ktlint-results.outputs.add_comment == 'true'
- uses: peter-evans/create-or-update-comment@v2
- with:
- comment-id: ${{ steps.fc.outputs.comment-id }}
- issue-number: ${{ github.event.pull_request.number }}
- body: |
- ### Ktlint Results
+ args: "--dangerfile tools/danger/dangerfile-lint.js"
+ env:
+ DANGER_GITHUB_API_TOKEN: ${{ secrets.DANGER_GITHUB_API_TOKEN }}
+ # Fallback for forks
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- ${{ steps.ktlint-results.outputs.body }}
- edit-mode: replace
- - name: Delete comment if needed
- if: always() && github.event_name == 'pull_request' && steps.fc.outputs.comment-id != '' && steps.ktlint-results.outputs.add_comment == 'false'
- uses: actions/github-script@v3
- with:
- script: |
- github.issues.deleteComment({
- owner: context.repo.owner,
- repo: context.repo.repo,
- comment_id: ${{ steps.fc.outputs.comment-id }}
- })
-
-# Gradle dependency analysis using https://github.com/autonomousapps/dependency-analysis-android-gradle-plugin
+ # Gradle dependency analysis using https://github.com/autonomousapps/dependency-analysis-android-gradle-plugin
dependency-analysis:
name: Dependency analysis
runs-on: ubuntu-latest
@@ -113,91 +85,10 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Dependency analysis
- run: ./gradlew buildHealth $CI_GRADLE_ARG_PROPERTIES
+ run: ./gradlew dependencyCheckAnalyze $CI_GRADLE_ARG_PROPERTIES
- name: Upload dependency analysis
if: always()
uses: actions/upload-artifact@v3
with:
name: dependency-analysis
- path: build/reports/dependency-analysis/build-health-report.txt
-
-# Lint for main module
- android-lint:
- name: Android Linter
- runs-on: ubuntu-latest
- # Allow all jobs on main and develop. Just one per PR.
- concurrency:
- group: ${{ github.ref == 'refs/heads/main' && format('android-lint-main-{0}', github.sha) || github.ref == 'refs/heads/develop' && format('android-lint-develop-{0}', github.sha) || format('android-lint-{0}', github.ref) }}
- cancel-in-progress: true
- steps:
- - uses: actions/checkout@v3
- - uses: actions/cache@v3
- with:
- path: |
- ~/.gradle/caches
- ~/.gradle/wrapper
- key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
- restore-keys: |
- ${{ runner.os }}-gradle-
- - name: Lint analysis
- run: ./gradlew clean :vector:lint --stacktrace
- - name: Upload reports
- if: always()
- uses: actions/upload-artifact@v3
- with:
- name: lint-report
- path: |
- vector/build/reports/*.*
-
-# Lint for Gplay and Fdroid release APK
- apk-lint:
- name: Lint APK (${{ matrix.target }})
- runs-on: ubuntu-latest
- if: github.ref != 'refs/heads/main'
- strategy:
- fail-fast: false
- matrix:
- target: [ Gplay, Fdroid ]
- # Allow all jobs on develop. Just one per PR.
- concurrency:
- group: ${{ github.ref == 'refs/heads/develop' && format('apk-lint-develop-{0}-{1}', matrix.target, github.sha) || format('apk-lint-{0}-{1}', matrix.target, github.ref) }}
- cancel-in-progress: true
- steps:
- - uses: actions/checkout@v3
- - uses: actions/cache@v3
- with:
- path: |
- ~/.gradle/caches
- ~/.gradle/wrapper
- key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
- restore-keys: |
- ${{ runner.os }}-gradle-
- - name: Lint ${{ matrix.target }} release
- run: ./gradlew clean lint${{ matrix.target }}Release --stacktrace
- - name: Upload ${{ matrix.target }} linting report
- if: always()
- uses: actions/upload-artifact@v3
- with:
- name: release-lint-report-${{ matrix.target }}
- path: |
- vector/build/reports/*.*
-
- detekt:
- name: Detekt Analysis
- runs-on: ubuntu-latest
- # Allow all jobs on main and develop. Just one per PR.
- concurrency:
- group: ${{ github.ref == 'refs/heads/main' && format('detekt-main-{0}', github.sha) || github.ref == 'refs/heads/develop' && format('detekt-develop-{0}', github.sha) || format('detekt-{0}', github.ref) }}
- cancel-in-progress: true
- steps:
- - uses: actions/checkout@v3
- - name: Run detekt
- run: |
- ./gradlew detekt
- - name: Upload reports
- if: always()
- uses: actions/upload-artifact@v3
- with:
- name: detekt-report
- path: |
- */build/reports/detekt/detekt.html
+ path: build/reports/dependency-check-report.html
diff --git a/.github/workflows/sync-from-external-sources.yml b/.github/workflows/sync-from-external-sources.yml
index 796d915ea6..fdc1bbcb96 100644
--- a/.github/workflows/sync-from-external-sources.yml
+++ b/.github/workflows/sync-from-external-sources.yml
@@ -13,7 +13,7 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Set up Python 3.8
- uses: actions/setup-python@v3
+ uses: actions/setup-python@v4
with:
python-version: 3.8
- name: Install Prerequisite dependencies
@@ -40,7 +40,7 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Set up Python 3.8
- uses: actions/setup-python@v3
+ uses: actions/setup-python@v4
with:
python-version: 3.8
- name: Install Prerequisite dependencies
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 5959fe9bb3..2a89ed3040 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -7,9 +7,8 @@ on:
# Enrich gradle.properties for CI/CD
env:
- CI_GRADLE_ARG_PROPERTIES: >
- -Porg.gradle.jvmargs=-Xmx2g
- -Porg.gradle.parallel=false
+ GRADLE_OPTS: -Dorg.gradle.jvmargs="-Xmx3072m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError" -Dkotlin.daemon.jvm.options="-Xmx2560m" -Dkotlin.incremental=false
+ CI_GRADLE_ARG_PROPERTIES: --stacktrace -PpreDexEnable=false --max-workers 2 --no-daemon
jobs:
tests:
@@ -28,7 +27,7 @@ jobs:
distribution: 'adopt'
java-version: '11'
- uses: gradle/gradle-build-action@v2
- - uses: actions/setup-python@v3
+ - uses: actions/setup-python@v4
with:
python-version: 3.8
- uses: michaelkaye/setup-matrix-synapse@v1.0.3
@@ -40,6 +39,7 @@ jobs:
- name: Run all the codecoverage tests at once
id: tests
uses: reactivecircus/android-emulator-runner@v2
+ continue-on-error: true
with:
api-level: 28
arch: x86
@@ -48,7 +48,11 @@ jobs:
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
disable-animations: true
emulator-build: 7425822
- script: ./gradlew theCodeCoverageReport --stacktrace $CI_GRADLE_ARG_PROPERTIES
+ script: |
+ ./gradlew unitTestsWithCoverage $CI_GRADLE_ARG_PROPERTIES
+ ./gradlew instrumentationTestsWithCoverage $CI_GRADLE_ARG_PROPERTIES
+ ./gradlew generateCoverageReport $CI_GRADLE_ARG_PROPERTIES
+# NB: continue-on-error marks steps.tests.conclusion = 'success' but leaves stes.tests.outcome = 'failure'
- name: Run all the codecoverage tests at once (retry if emulator failed)
uses: reactivecircus/android-emulator-runner@v2
if: always() && steps.tests.outcome == 'failure' # don't run if previous step succeeded.
@@ -60,11 +64,14 @@ jobs:
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
disable-animations: true
emulator-build: 7425822
- script: ./gradlew theCodeCoverageReport --stacktrace $CI_GRADLE_ARG_PROPERTIES
+ script: |
+ ./gradlew unitTestsWithCoverage $CI_GRADLE_ARG_PROPERTIES
+ ./gradlew instrumentationTestsWithCoverage $CI_GRADLE_ARG_PROPERTIES
+ ./gradlew generateCoverageReport $CI_GRADLE_ARG_PROPERTIES
- run: ./gradlew sonarqube $CI_GRADLE_ARG_PROPERTIES
if: always() # we may have failed a previous step and retried, that's OK
env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
+ GITHUB_TOKEN: ${{ secrets.SONARQUBE_GITHUB_API_TOKEN }} # Needed to get PR information, if any
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
ORG_GRADLE_PROJECT_SONAR_LOGIN: ${{ secrets.SONAR_TOKEN }}
@@ -105,5 +112,5 @@ jobs:
# restore-keys: |
# ${{ runner.os }}-gradle-
# - name: Build Android Tests
-# run: ./gradlew clean assembleAndroidTest $CI_GRADLE_ARG_PROPERTIES --stacktrace
+# run: ./gradlew clean assembleAndroidTest $CI_GRADLE_ARG_PROPERTIES
diff --git a/.github/workflows/triage-labelled.yml b/.github/workflows/triage-labelled.yml
index c49b33d582..90f03779a6 100644
--- a/.github/workflows/triage-labelled.yml
+++ b/.github/workflows/triage-labelled.yml
@@ -42,20 +42,13 @@ jobs:
column-name: "Need info"
label-name: "X-Needs-Info"
- add_priority_design_issues_to_project:
- name: P1 X-Needs-Design to Design project board
+ add_design_issues_to_project:
+ name: X-Needs-Design to Design project board
runs-on: ubuntu-latest
# Skip in forks
if: >
github.repository == 'vector-im/element-android' &&
- contains(github.event.issue.labels.*.name, 'X-Needs-Design') &&
- (contains(github.event.issue.labels.*.name, 'S-Critical') &&
- (contains(github.event.issue.labels.*.name, 'O-Frequent') ||
- contains(github.event.issue.labels.*.name, 'O-Occasional')) ||
- contains(github.event.issue.labels.*.name, 'S-Major') &&
- contains(github.event.issue.labels.*.name, 'O-Frequent') ||
- contains(github.event.issue.labels.*.name, 'A11y') &&
- contains(github.event.issue.labels.*.name, 'O-Frequent'))
+ contains(github.event.issue.labels.*.name, 'X-Needs-Design')
steps:
- uses: octokit/graphql-action@v2.x
id: add_to_project
@@ -255,9 +248,12 @@ jobs:
# 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'))
+ (contains(github.event.issue.labels.*.name, 'Z-BBQ-Alpha') ||
+ contains(github.event.issue.labels.*.name, 'Z-BBQ-Beta') ||
+ contains(github.event.issue.labels.*.name, 'Z-BBQ-Release') ||
+ contains(github.event.issue.labels.*.name, 'Z-Banquet-Alpha') ||
+ contains(github.event.issue.labels.*.name, 'Z-Banquet-Beta') ||
+ contains(github.event.issue.labels.*.name, 'Z-Banquet-Release'))
steps:
- uses: octokit/graphql-action@v2.x
with:
diff --git a/.github/workflows/triage-priority-bugs.yml b/.github/workflows/triage-priority-bugs.yml
index 43e11edca5..6cde154370 100644
--- a/.github/workflows/triage-priority-bugs.yml
+++ b/.github/workflows/triage-priority-bugs.yml
@@ -14,7 +14,7 @@ jobs:
!contains(github.event.issue.labels.*.name, 'A-E2EE-Cross-Signing') &&
!contains(github.event.issue.labels.*.name, 'A-E2EE-Dehydration') &&
!contains(github.event.issue.labels.*.name, 'A-E2EE-Key-Backup') &&
- !contains(github.event.issue.labels.*.name, 'A-E2EE-SAS-Verification') &&
+ !contains(github.event.issue.labels.*.name, 'A-E2EE-SAS-Verification')) &&
(contains(github.event.issue.labels.*.name, 'T-Defect') &&
contains(github.event.issue.labels.*.name, 'S-Critical') &&
(contains(github.event.issue.labels.*.name, 'O-Frequent') ||
diff --git a/.gitignore b/.gitignore
index ff086d7723..f1c0b99b58 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,4 +16,9 @@
/fastlane/private
/fastlane/report.xml
-/library/build
+/**/build
+
+# Added by yarn
+/package.json
+/yarn.lock
+/node_modules
diff --git a/.idea/dictionaries/bmarty.xml b/.idea/dictionaries/bmarty.xml
index 85290e72df..c29bca95f2 100644
--- a/.idea/dictionaries/bmarty.xml
+++ b/.idea/dictionaries/bmarty.xml
@@ -40,6 +40,7 @@
sygnal
threepid
uisi
+ unifiedpush
unpublish
unwedging
vctr
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 6e67639284..0000000000
--- a/.travis.yml
+++ /dev/null
@@ -1,18 +0,0 @@
-# FTR: Configuration on https://travis-ci.org/github/vector-im/element-android/settings
-#
-# - Build only if .travis.yml is present -> On
-# - Limit concurrent jobs -> Off
-# - Build pushed branches -> On (build the branch)
-# - Build pushed pull request -> On (build the PR after auto-merge)
-#
-# - Auto cancel branch builds -> On
-# - Auto cancel pull request builds -> On
-
-sudo: false
-
-notifications:
- email: false
-
-# Just run a simple script here
-script:
- - ./tools/travis/check_pr.sh
diff --git a/CHANGES.md b/CHANGES.md
index 166453dfad..829b1a0caa 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,3 +1,282 @@
+Changes in Element v1.4.32 (2022-08-10)
+=======================================
+
+Features ✨
+----------
+ - [Location Share] Render fallback UI when map fails to load ([#6711](https://github.com/vector-im/element-android/issues/6711))
+
+Bugfixes 🐛
+----------
+ - Fix message content sometimes appearing in the log ([#6706](https://github.com/vector-im/element-android/issues/6706))
+ - Disable 'Enable biometrics' option if there are not biometric authenticators enrolled. ([#6713](https://github.com/vector-im/element-android/issues/6713))
+ - Fix crash when biometric key is used when coming back to foreground and KeyStore reports that the device is still locked. ([#6768](https://github.com/vector-im/element-android/issues/6768))
+ - Catch all exceptions on lockscreen system key migrations. ([#6769](https://github.com/vector-im/element-android/issues/6769))
+ - Fixes crash when entering non ascii characters during account creation ([#6735](https://github.com/vector-im/element-android/issues/6735))
+ - Fixes onboarding login/account creation errors showing after navigation ([#6737](https://github.com/vector-im/element-android/issues/6737))
+ - [Location sharing] Invisible text on map symbol ([#6687](https://github.com/vector-im/element-android/issues/6687))
+
+In development 🚧
+----------------
+ - Adds new app layout toolbar ([#6655](https://github.com/vector-im/element-android/issues/6655))
+
+Other changes
+-------------
+ - [Modularization] Provides abstraction to avoid direct usages of BuildConfig ([#6406](https://github.com/vector-im/element-android/issues/6406))
+ - Refactors SpaceStateHandler (previously AppStateHandler) and adds unit tests for it ([#6598](https://github.com/vector-im/element-android/issues/6598))
+ - Setup Danger to the project ([#6637](https://github.com/vector-im/element-android/issues/6637))
+ - [Location Share] Open maximized map on tapping on live sharing notification ([#6642](https://github.com/vector-im/element-android/issues/6642))
+ - [Location sharing] Align naming of components for live location feature ([#6647](https://github.com/vector-im/element-android/issues/6647))
+ - [Location share] Update minimum sending period to 5 seconds for a live ([#6653](https://github.com/vector-im/element-android/issues/6653))
+ - [Location sharing] - Fix the memory leaks ([#6674](https://github.com/vector-im/element-android/issues/6674))
+ - [Timeline] Memory leak in audio message playback tracker ([#6678](https://github.com/vector-im/element-android/issues/6678))
+ - [FTUE] Memory leak on FtueAuthSplashCarouselFragment ([#6680](https://github.com/vector-im/element-android/issues/6680))
+ - Link directly to DCO docs from danger message. ([#6739](https://github.com/vector-im/element-android/issues/6739))
+
+
+Changes in Element v1.4.31 (2022-08-01)
+=======================================
+
+Bugfixes 🐛
+----------
+ - Fixes crash when returning to the app after backgrounding ([#6709](https://github.com/vector-im/element-android/issues/6709))
+ - Fix message content sometimes appearing in the log ([#6706](https://github.com/vector-im/element-android/issues/6706))
+
+
+Changes in Element v1.4.30 (2022-07-29)
+=======================================
+
+Features ✨
+----------
+ - [FTUE] - Enable improved login and register onboarding flows ([#2585](https://github.com/vector-im/element-android/issues/2585))
+ - Adds settings screen to change app font scale or enable using system setting ([#5687](https://github.com/vector-im/element-android/issues/5687))
+ - [Location sharing] - Delete action on a live message ([#6437](https://github.com/vector-im/element-android/issues/6437))
+ - [Timeline] - Collapse redacted events ([#6487](https://github.com/vector-im/element-android/issues/6487))
+ - Improve lock screen implementation with extra security measures ([#6522](https://github.com/vector-im/element-android/issues/6522))
+ - Move initialization of the Session to a background thread. MainActivity is restoring the session now, instead of VectorApplication. Useful when for instance a long migration of a database is required. ([#6548](https://github.com/vector-im/element-android/issues/6548))
+ - Share location with other apps ([#6567](https://github.com/vector-im/element-android/issues/6567))
+ - Support element call widget ([#6616](https://github.com/vector-im/element-android/issues/6616))
+ - [FTUE] Updates FTUE registration to include username availability check and update copy ([#6546](https://github.com/vector-im/element-android/issues/6546))
+ - [FTUE] - Allows the email address to be changed during the verification process ([#6622](https://github.com/vector-im/element-android/issues/6622))
+ - [FTUE] Updates the copy within the FTUE onboarding ([#6547](https://github.com/vector-im/element-android/issues/6547))
+ - [FTUE] Test session feedback ([#6620](https://github.com/vector-im/element-android/issues/6620))
+ - [FTUE] - Improved reset password error message ([#6621](https://github.com/vector-im/element-android/issues/6621))
+
+Bugfixes 🐛
+----------
+ - Fixes wrong voice message being displayed and played on the timeline. ([#6213](https://github.com/vector-im/element-android/issues/6213))
+ - Fixes the room list not taking into account the Show all rooms in Home preference ([#6665](https://github.com/vector-im/element-android/issues/6665))
+ - Stop using unstable names for withheld codes ([#5115](https://github.com/vector-im/element-android/issues/5115))
+ - Fixes room not being in space after upgrade ([#6200](https://github.com/vector-im/element-android/issues/6200))
+ - Fixed issues with reporting sync state events from different threads ([#6341](https://github.com/vector-im/element-android/issues/6341))
+ - Display specific message when verification QR code is malformed ([#6395](https://github.com/vector-im/element-android/issues/6395))
+ - When there is no way to verify a device (no 4S nor other device) propose to reset verification keys ([#6466](https://github.com/vector-im/element-android/issues/6466))
+ - Unwedging could cause the SDK to force creating a new olm session every hour ([#6534](https://github.com/vector-im/element-android/issues/6534))
+ - [Location Share] - Wrong room live location status bar visibility in timeline ([#6537](https://github.com/vector-im/element-android/issues/6537))
+ - Fix infinite loading when opening a DM when the current room is the same DM. ([#6549](https://github.com/vector-im/element-android/issues/6549))
+ - Do not log the live location of the user ([#6579](https://github.com/vector-im/element-android/issues/6579))
+ - Fix backup saving several times the same keys ([#6585](https://github.com/vector-im/element-android/issues/6585))
+ - Check user power level before sharing live location ([#6587](https://github.com/vector-im/element-android/issues/6587))
+ - [Location Share] - Live is considered as ended while still active ([#6596](https://github.com/vector-im/element-android/issues/6596))
+ - Put EC permission shortcuts behind labs flag (PSG-630) ([#6634](https://github.com/vector-im/element-android/issues/6634))
+ - ObjectAnimators are not canceled in TypingMessageDotsView ([#6663](https://github.com/vector-im/element-android/issues/6663))
+
+SDK API changes ⚠️
+------------------
+ - Communities/Groups are removed completely ([#5733](https://github.com/vector-im/element-android/issues/5733))
+ - SDK - The SpaceFilter is query parameter is no longer nullable, use SpaceFilter.NoFilter instead ([#6666](https://github.com/vector-im/element-android/issues/6666))
+
+Other changes
+-------------
+ - Nightly build publication on Firebase ([#6478](https://github.com/vector-im/element-android/issues/6478))
+ - Communities/Groups are removed completely ([#5733](https://github.com/vector-im/element-android/issues/5733))
+ - Improves performance on search screen by replacing flattenParents with directParentName in RoomSummary ([#6314](https://github.com/vector-im/element-android/issues/6314))
+ - Log durations of DB migration and migration steps. ([#6538](https://github.com/vector-im/element-android/issues/6538))
+ - [Location Share] - Standardise "Stop" texts for live ([#6541](https://github.com/vector-im/element-android/issues/6541))
+ - Adds NewAppLayoutEnabled feature flag ([#6584](https://github.com/vector-im/element-android/issues/6584))
+ - [Location sharing] - Small improvements of UI for live ([#6607](https://github.com/vector-im/element-android/issues/6607))
+ - Live Location Sharing - Reset zoom level while focusing a user ([#6609](https://github.com/vector-im/element-android/issues/6609))
+ - Fix a typo in the terms and conditions step during registration. ([#6612](https://github.com/vector-im/element-android/issues/6612))
+ - [Location sharing] - OnTap on the top live status bar, display the expanded map view ([#6625](https://github.com/vector-im/element-android/issues/6625))
+ - [Location Share] - Expanded map state when no more live location shares ([#6635](https://github.com/vector-im/element-android/issues/6635))
+
+
+Changes in Element v1.4.28 (2022-07-13)
+=======================================
+
+Features ✨
+----------
+ - Improve user experience when he is first invited to a room. Users will be able to decrypt and view previous messages ([#5853](https://github.com/vector-im/element-android/issues/5853))
+ - [Location sharing] - Reply action on a live message ([#6401](https://github.com/vector-im/element-android/issues/6401))
+ - Show a loader if all the Room Members are not yet loaded. ([#6413](https://github.com/vector-im/element-android/issues/6413))
+
+Bugfixes 🐛
+----------
+ - Fixes numbered lists always starting from 1 ([#4777](https://github.com/vector-im/element-android/issues/4777))
+ - Adds LoginType to SessionParams to fix soft logout form not showing for SSO and Password type ([#5398](https://github.com/vector-im/element-android/issues/5398))
+ - Use stable endpoint for alias management instead of MSC2432. Contributed by Nico. ([#6288](https://github.com/vector-im/element-android/issues/6288))
+ - [Poll] Fixes visible and wrong votes in closed poll after removing 2 previous polls ([#6430](https://github.com/vector-im/element-android/issues/6430))
+ - Fix HTML entities being displayed in messages ([#6442](https://github.com/vector-im/element-android/issues/6442))
+ - Gallery picker can pick external images ([#6450](https://github.com/vector-im/element-android/issues/6450))
+ - Fixes crash when sharing plain text, such as a url ([#6451](https://github.com/vector-im/element-android/issues/6451))
+ - Fix crashes on Timeline [Thread] due to range validation ([#6461](https://github.com/vector-im/element-android/issues/6461))
+ - Fix crashes when opening Thread ([#6463](https://github.com/vector-im/element-android/issues/6463))
+ - Fix ConcurrentModificationException on BackgroundDetectionObserver ([#6469](https://github.com/vector-im/element-android/issues/6469))
+ - Fixes inconsistency with rooms within spaces showing or disappearing from home ([#6510](https://github.com/vector-im/element-android/issues/6510))
+
+In development 🚧
+----------------
+ - FTUE - Adds support for resetting the password during the FTUE onboarding journey ([#5284](https://github.com/vector-im/element-android/issues/5284))
+ - Create DM room only on first message - Design implementation & debug feature flag ([#5525](https://github.com/vector-im/element-android/issues/5525))
+
+Other changes
+-------------
+ - Replacing Epoxy annotation layout id references with getDefaultLayoutId ([#6389](https://github.com/vector-im/element-android/issues/6389))
+ - Ensure `RealmList.clearWith()` extension is correctly used. ([#6392](https://github.com/vector-im/element-android/issues/6392))
+ - [Poll] - Add a description under undisclosed poll when not ended ([#6423](https://github.com/vector-im/element-android/issues/6423))
+ - Add `android:hasFragileUserData="true"` in the manifest ([#6429](https://github.com/vector-im/element-android/issues/6429))
+ - Add code check to prevent modification of frozen class ([#6434](https://github.com/vector-im/element-android/issues/6434))
+ - Let your Activity or Fragment implement `VectorMenuProvider` if they provide a menu. ([#6436](https://github.com/vector-im/element-android/issues/6436))
+ - Rename Android Service to use `AndroidService` suffix ([#6458](https://github.com/vector-im/element-android/issues/6458))
+
+
+Changes in Element v1.4.27 (2022-07-06)
+=======================================
+
+Bugfixes 🐛
+----------
+ - Fixes crash when sharing plain text, such as a url ([#6451](https://github.com/vector-im/element-android/issues/6451))
+ - Fix crashes on Timeline [Thread] due to range validation ([#6461](https://github.com/vector-im/element-android/issues/6461))
+ - Fix crashes when opening Thread ([#6463](https://github.com/vector-im/element-android/issues/6463))
+ - Fix ConcurrentModificationException on BackgroundDetectionObserver ([#6469](https://github.com/vector-im/element-android/issues/6469))
+
+
+Changes in Element v1.4.26 (2022-06-30)
+=======================================
+
+Features ✨
+----------
+ - Use UnifiedPush and allows user to have push without FCM. ([#3448](https://github.com/vector-im/element-android/issues/3448))
+ - Replace ffmpeg-kit with libopus and libopusenc. ([#6203](https://github.com/vector-im/element-android/issues/6203))
+ - Improve lock screen implementation. ([#6217](https://github.com/vector-im/element-android/issues/6217))
+ - Allow sharing text based content via android's share menu (eg .ics files) ([#6285](https://github.com/vector-im/element-android/issues/6285))
+ - Promote live location labs flag ([#6350](https://github.com/vector-im/element-android/issues/6350))
+ - [Location sharing] - Stop any active live before starting a new one ([#6364](https://github.com/vector-im/element-android/issues/6364))
+ - Expose pusher profile tag in advanced settings ([#6369](https://github.com/vector-im/element-android/issues/6369))
+
+Bugfixes 🐛
+----------
+ - Fixes concurrent modification crash when signing out or launching the app ([#5821](https://github.com/vector-im/element-android/issues/5821))
+ - Refactor - better naming, return native user id and not sip user id and create a dm with the native user instead of with the sip user. ([#6101](https://github.com/vector-im/element-android/issues/6101))
+ - Fixed /upgraderoom command not doing anything ([#6154](https://github.com/vector-im/element-android/issues/6154))
+ - Fixed crash when opening large images in the timeline ([#6290](https://github.com/vector-im/element-android/issues/6290))
+ - [Location sharing] Fix crash when starting/stopping a live when offline ([#6315](https://github.com/vector-im/element-android/issues/6315))
+ - Fix loop in timeline and simplify management of chunks and timeline events. ([#6318](https://github.com/vector-im/element-android/issues/6318))
+ - Update design and behaviour on widget permission bottom sheet ([#6326](https://github.com/vector-im/element-android/issues/6326))
+ - Fix | Some user verification requests couldn't be accepted/declined ([#6328](https://github.com/vector-im/element-android/issues/6328))
+ - [Location sharing] Fix stop of a live not possible from another device ([#6349](https://github.com/vector-im/element-android/issues/6349))
+ - Fix backslash escapes in formatted messages ([#6357](https://github.com/vector-im/element-android/issues/6357))
+ - Fixes wrong error message when signing in with wrong credentials ([#6371](https://github.com/vector-im/element-android/issues/6371))
+ - [Location Share] - Adding missing prefix "u=" for uncertainty in geo URI ([#6375](https://github.com/vector-im/element-android/issues/6375))
+
+In development 🚧
+----------------
+ - FTUE - Adds automatic homeserver selection when typing a full matrix id during registration or login ([#6162](https://github.com/vector-im/element-android/issues/6162))
+
+Improved Documentation 📚
+------------------------
+ - Update the PR process doc to come back to one reviewer with optional additional reviewers. ([#6396](https://github.com/vector-im/element-android/issues/6396))
+
+SDK API changes ⚠️
+------------------
+ - Group all location sharing related API into LocationSharingService ([#5864](https://github.com/vector-im/element-android/issues/5864))
+ - Add support for MSC2457 - opting in or out of logging out all devices when changing password ([#6191](https://github.com/vector-im/element-android/issues/6191))
+ - Create `QueryStateEventValue` to do query on `stateKey` for State Event. Also remove the default parameter values for those type. ([#6319](https://github.com/vector-im/element-android/issues/6319))
+
+Other changes
+-------------
+ - - Notify of the latest known location in LocationTracker to avoid multiple locations at start
+ - Debounce location updates
+ - Improve location providers access ([#5913](https://github.com/vector-im/element-android/issues/5913))
+ - Add unit tests for LiveLocationAggregationProcessor code ([#6155](https://github.com/vector-im/element-android/issues/6155))
+ - Making screenshots in bug reports opt in instead of opt out ([#6261](https://github.com/vector-im/element-android/issues/6261))
+ - Setup [Flipper](https://fbflipper.com/) ([#6300](https://github.com/vector-im/element-android/issues/6300))
+ - CreatePollViewModel unit tests ([#6320](https://github.com/vector-im/element-android/issues/6320))
+ - Fix flaky test in voice recording feature. ([#6329](https://github.com/vector-im/element-android/issues/6329))
+ - Poll view state unit tests ([#6366](https://github.com/vector-im/element-android/issues/6366))
+ - Let LoadRoomMembersTask insert by chunk to release db. ([#6394](https://github.com/vector-im/element-android/issues/6394))
+
+
+Changes in Element v1.4.25 (2022-06-27)
+=======================================
+
+Bugfixes 🐛
+----------
+- Second attempt to fix session database migration to version 30.
+
+Changes in Element v1.4.24 (2022-06-22)
+=======================================
+
+Bugfixes 🐛
+----------
+- First attempt to fix session database migration to version 30.
+
+Changes in Element v1.4.23 (2022-06-21)
+=======================================
+
+Bugfixes 🐛
+----------
+ - Fix loop in timeline and simplify management of chunks and timeline events. ([#6318](https://github.com/vector-im/element-android/issues/6318))
+
+
+Changes in Element v1.4.22 (2022-06-14)
+=======================================
+
+Features ✨
+----------
+ - Make read receipt avatar list more compact ([#5970](https://github.com/vector-im/element-android/issues/5970))
+ - Allow .well-known configuration to override key sharing mode ([#6147](https://github.com/vector-im/element-android/issues/6147))
+ - Re-organize location settings flags ([#6244](https://github.com/vector-im/element-android/issues/6244))
+ - Add report action for live location messages ([#6280](https://github.com/vector-im/element-android/issues/6280))
+
+Bugfixes 🐛
+----------
+ - Fix cases of missing, swapped, or duplicated messages ([#5528](https://github.com/vector-im/element-android/issues/5528))
+ - Fix wrong status of live location sharing in timeline ([#6209](https://github.com/vector-im/element-android/issues/6209))
+ - Fix StackOverflowError while recording voice message ([#6222](https://github.com/vector-im/element-android/issues/6222))
+ - Text cropped: "Secure backup" ([#6232](https://github.com/vector-im/element-android/issues/6232))
+ - Fix copyright attributions of map views ([#6247](https://github.com/vector-im/element-android/issues/6247))
+ - Fix flickering bottom bar of live location item ([#6264](https://github.com/vector-im/element-android/issues/6264))
+
+In development 🚧
+----------------
+ - FTUE - Adds Sign Up tracking ([#5285](https://github.com/vector-im/element-android/issues/5285))
+
+SDK API changes ⚠️
+------------------
+ - Some methods from `Session` have been moved to a new `SyncService`, that you can retrieve from a `Session`.
+ - `SyncStatusService` method has been moved to the new `SyncService`
+ - `InitSyncStep` have been moved and renamed to `InitialSyncStep`
+ - `SyncStatusService.Status` has been renamed to `SyncRequestState`
+ - The existing `SyncService` has been renamed to `SyncAndroidService` because of name clash with the new SDK Service ([#6029](https://github.com/vector-im/element-android/issues/6029))
+ - Allows `AuthenticationService.getLoginFlow` to fail without resetting state from previously successful calls ([#6093](https://github.com/vector-im/element-android/issues/6093))
+ - Allows new passwords to be passed at the point of confirmation when resetting a password ([#6169](https://github.com/vector-im/element-android/issues/6169))
+
+Other changes
+-------------
+ - Adds support for parsing homeserver versions without a patch number ([#6017](https://github.com/vector-im/element-android/issues/6017))
+ - Updating exit onboarding dialog copy formatting to match iOS ([#6087](https://github.com/vector-im/element-android/issues/6087))
+ - Disables when arrow alignment in code style ([#6126](https://github.com/vector-im/element-android/issues/6126))
+
+
+Changes in Element 1.4.20 (2022-06-13)
+======================================
+
+Bugfixes 🐛
+----------
+ - Fix: All rooms are shown in Home regardless of the switch state. ([#6272](https://github.com/vector-im/element-android/issues/6272))
+ - Fix regression on EventInsertLiveObserver getting blocked so there is no event being processed anymore. ([#6278](https://github.com/vector-im/element-android/issues/6278))
+
+
Changes in Element 1.4.19 (2022-06-07)
======================================
diff --git a/Gemfile b/Gemfile
index 7a118b49be..c90138ee44 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,3 +1,4 @@
source "https://rubygems.org"
gem "fastlane"
+gem 'danger'
diff --git a/Gemfile.lock b/Gemfile.lock
index 2ac9762eac..d4beadae81 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -25,10 +25,29 @@ GEM
aws-eventstream (~> 1, >= 1.0.2)
babosa (1.0.4)
claide (1.1.0)
+ claide-plugins (0.9.2)
+ cork
+ nap
+ open4 (~> 1.3)
colored (1.2)
colored2 (3.1.2)
commander (4.6.0)
highline (~> 2.0.0)
+ cork (0.3.0)
+ colored2 (~> 3.1)
+ danger (8.6.1)
+ claide (~> 1.0)
+ claide-plugins (>= 0.9.2)
+ colored2 (~> 3.1)
+ cork (~> 0.1)
+ faraday (>= 0.9.0, < 2.0)
+ faraday-http-cache (~> 2.0)
+ git (~> 1.7)
+ kramdown (~> 2.3)
+ kramdown-parser-gfm (~> 1.0)
+ no_proxy_fix
+ octokit (~> 4.7)
+ terminal-table (>= 1, < 4)
declarative (0.0.20)
digest-crc (0.6.4)
rake (>= 12.0.0, < 14.0.0)
@@ -55,6 +74,8 @@ GEM
faraday-em_http (1.0.0)
faraday-em_synchrony (1.0.0)
faraday-excon (1.1.0)
+ faraday-http-cache (2.4.0)
+ faraday (>= 0.8)
faraday-httpclient (1.0.1)
faraday-multipart (1.0.4)
multipart-post (~> 2)
@@ -106,6 +127,8 @@ GEM
xcpretty (~> 0.3.0)
xcpretty-travis-formatter (>= 0.0.3)
gh_inspector (1.1.3)
+ git (1.11.0)
+ rchardet (~> 1.8)
google-apis-androidpublisher_v3 (0.22.0)
google-apis-core (>= 0.5, < 2.a)
google-apis-core (0.6.0)
@@ -151,18 +174,29 @@ GEM
jmespath (1.6.1)
json (2.6.2)
jwt (2.4.1)
+ kramdown (2.4.0)
+ rexml
+ kramdown-parser-gfm (1.1.0)
+ kramdown (~> 2.0)
memoist (0.16.2)
mini_magick (4.11.0)
mini_mime (1.1.2)
multi_json (1.15.0)
multipart-post (2.0.0)
nanaimo (0.3.0)
+ nap (1.1.0)
naturally (2.2.1)
+ no_proxy_fix (0.1.2)
+ octokit (4.25.1)
+ faraday (>= 1, < 3)
+ sawyer (~> 0.9)
+ open4 (1.3.4)
optparse (0.1.1)
os (1.1.4)
plist (3.6.0)
public_suffix (4.0.7)
rake (13.0.6)
+ rchardet (1.8.0)
representable (3.2.0)
declarative (< 0.1.0)
trailblazer-option (>= 0.1.1, < 0.2.0)
@@ -172,6 +206,9 @@ GEM
rouge (2.0.7)
ruby2_keywords (0.0.5)
rubyzip (2.3.2)
+ sawyer (0.9.2)
+ addressable (>= 2.3.5)
+ faraday (>= 0.17.3, < 3)
security (0.1.3)
signet (0.16.1)
addressable (~> 2.8)
@@ -209,10 +246,12 @@ GEM
xcpretty (~> 0.2, >= 0.0.7)
PLATFORMS
+ universal-darwin-21
x86_64-darwin-20
x86_64-linux
DEPENDENCIES
+ danger
fastlane
BUNDLED WITH
diff --git a/build.gradle b/build.gradle
index 03e175927c..6ef6ef0a33 100644
--- a/build.gradle
+++ b/build.gradle
@@ -24,12 +24,13 @@ buildscript {
classpath libs.gradle.gradlePlugin
classpath libs.gradle.kotlinPlugin
classpath libs.gradle.hiltPlugin
- classpath 'com.google.gms:google-services:4.3.10'
- classpath 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.3'
+ classpath 'com.google.firebase:firebase-appdistribution-gradle:3.0.2'
+ classpath 'com.google.gms:google-services:4.3.13'
+ classpath 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.4.0.2513'
classpath 'com.google.android.gms:oss-licenses-plugin:0.10.5'
classpath "com.likethesalad.android:stem-plugin:2.1.1"
- classpath 'org.owasp:dependency-check-gradle:7.1.0.1'
- classpath "org.jetbrains.dokka:dokka-gradle-plugin:1.6.21"
+ classpath 'org.owasp:dependency-check-gradle:7.1.1'
+ classpath "org.jetbrains.dokka:dokka-gradle-plugin:1.7.10"
classpath "org.jetbrains.kotlinx:kotlinx-knit:0.4.0"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
@@ -40,10 +41,10 @@ plugins {
// ktlint Plugin
id "org.jlleitschuh.gradle.ktlint" version "10.3.0"
// Detekt
- id "io.gitlab.arturbosch.detekt" version "1.20.0"
+ id "io.gitlab.arturbosch.detekt" version "1.21.0"
// Dependency Analysis
- id 'com.autonomousapps.dependency-analysis' version "1.4.0"
+ id 'com.autonomousapps.dependency-analysis' version "1.11.2"
}
// https://github.com/jeremylong/DependencyCheck
@@ -125,6 +126,11 @@ allprojects {
enableExperimentalRules = true
// display the corresponding rule
verbose = true
+ reporters {
+ reporter(org.jlleitschuh.gradle.ktlint.reporter.ReporterType.PLAIN)
+ // To have XML report for Danger
+ reporter(org.jlleitschuh.gradle.ktlint.reporter.ReporterType.CHECKSTYLE)
+ }
disabledRules = [
// TODO Re-enable these 4 rules after reformatting project
"indent",
@@ -145,6 +151,8 @@ allprojects {
"experimental:comment-wrapping",
// - A KDoc comment after any other element on the same line must be separated by a new line
"experimental:kdoc-wrapping",
+ // Ignore error "Redundant curly braces", since we use it to fix false positives, for instance in "elementLogs.${i}.txt"
+ "string-template",
]
}
@@ -168,7 +176,7 @@ def launchTask = getGradle()
.toString()
.toLowerCase()
-if (launchTask.contains("codeCoverageReport".toLowerCase())) {
+if (launchTask.contains("coverage".toLowerCase())) {
apply from: 'coverage.gradle'
}
@@ -191,7 +199,7 @@ sonarqube {
property "sonar.links.issue", "https://github.com/vector-im/element-android/issues"
property "sonar.organization", "new_vector_ltd_organization"
property "sonar.java.coveragePlugin", "jacoco"
- property "sonar.coverage.jacoco.xmlReportPaths", "${project.buildDir}/reports/jacoco/theCodeCoverageReport/theCodeCoverageReport.xml"
+ property "sonar.coverage.jacoco.xmlReportPaths", "${project.buildDir}/reports/jacoco/generateCoverageReport/generateCoverageReport.xml"
property "sonar.login", project.hasProperty("SONAR_LOGIN") ? SONAR_LOGIN : "invalid"
}
}
@@ -252,11 +260,7 @@ dependencyAnalysis {
exclude("org.json:json") // Used in unit tests, overwrites the one bundled into Android
}
}
- project(":library:ui-styles") {
- onUnusedDependencies {
- exclude("com.github.vector-im:PFLockScreen-Android") // False positive
- }
- }
+ project(":library:ui-styles")
project(":matrix-sdk-android") {
onUnusedDependencies {
exclude("io.reactivex.rxjava2:rxkotlin") // Transitively required for mocking realm as monarchy doesn't expose Rx
@@ -271,6 +275,8 @@ dependencyAnalysis {
onUnusedDependencies {
// False positives
exclude(
+ "androidx.fragment:fragment-testing",
+ "com.facebook.soloader:soloader",
"com.vanniktech:emoji-google",
"com.vanniktech:emoji-material",
"org.maplibre.gl:android-plugin-annotation-v9",
diff --git a/changelog.d/5285.wip b/changelog.d/5285.wip
deleted file mode 100644
index 1dd68597be..0000000000
--- a/changelog.d/5285.wip
+++ /dev/null
@@ -1 +0,0 @@
-FTUE - Adds Sign Up tracking
diff --git a/changelog.d/5528.bugfix b/changelog.d/5528.bugfix
deleted file mode 100644
index b0dc759ab0..0000000000
--- a/changelog.d/5528.bugfix
+++ /dev/null
@@ -1 +0,0 @@
-Fix cases of missing, swapped, or duplicated messages
diff --git a/changelog.d/5970.feature b/changelog.d/5970.feature
deleted file mode 100644
index b65decdd2d..0000000000
--- a/changelog.d/5970.feature
+++ /dev/null
@@ -1 +0,0 @@
-Make read receipt avatar list more compact
diff --git a/changelog.d/5974.misc b/changelog.d/5974.misc
new file mode 100644
index 0000000000..d2ddef6f1d
--- /dev/null
+++ b/changelog.d/5974.misc
@@ -0,0 +1 @@
+Removes the Login2 proof of concept - replaced by the FTUE changes
diff --git a/changelog.d/6017.misc b/changelog.d/6017.misc
deleted file mode 100644
index 2597f2d796..0000000000
--- a/changelog.d/6017.misc
+++ /dev/null
@@ -1 +0,0 @@
-Adds support for parsing homeserver versions without a patch number
diff --git a/changelog.d/6093.sdk b/changelog.d/6093.sdk
deleted file mode 100644
index 8ac5e41b61..0000000000
--- a/changelog.d/6093.sdk
+++ /dev/null
@@ -1 +0,0 @@
-Allowing AuthenticationService.getLoginFlow to fail without resetting state from previously successful calls
diff --git a/changelog.d/6146.feature b/changelog.d/6146.feature
deleted file mode 100644
index 9d1e117ddb..0000000000
--- a/changelog.d/6146.feature
+++ /dev/null
@@ -1 +0,0 @@
-Allow .well-known configuration to override key sharing mode
diff --git a/changelog.d/6169.sdk b/changelog.d/6169.sdk
deleted file mode 100644
index dfee158c3f..0000000000
--- a/changelog.d/6169.sdk
+++ /dev/null
@@ -1 +0,0 @@
-Allows new passwords to be passed at the point of confirmation when resetting a password
diff --git a/changelog.d/6222.bugfix b/changelog.d/6222.bugfix
deleted file mode 100644
index ef430ee024..0000000000
--- a/changelog.d/6222.bugfix
+++ /dev/null
@@ -1 +0,0 @@
-Fix StackOverflowError while recording voice message
diff --git a/changelog.d/6232.bugfix b/changelog.d/6232.bugfix
deleted file mode 100644
index df04655701..0000000000
--- a/changelog.d/6232.bugfix
+++ /dev/null
@@ -1 +0,0 @@
-Text cropped: "Secure backup"
diff --git a/changelog.d/6505.wip b/changelog.d/6505.wip
new file mode 100644
index 0000000000..1109c5fff1
--- /dev/null
+++ b/changelog.d/6505.wip
@@ -0,0 +1 @@
+added filter tabs for new App layout's Home screen
diff --git a/changelog.d/6645.misc b/changelog.d/6645.misc
new file mode 100644
index 0000000000..b24655879d
--- /dev/null
+++ b/changelog.d/6645.misc
@@ -0,0 +1 @@
+Enable auto-capitalization for Room creation Title field
diff --git a/changelog.d/6693.feature b/changelog.d/6693.feature
new file mode 100644
index 0000000000..5e905766a9
--- /dev/null
+++ b/changelog.d/6693.feature
@@ -0,0 +1 @@
+Adds New App Layout FABs (hidden behind feature flag)
diff --git a/changelog.d/6746.feature b/changelog.d/6746.feature
new file mode 100644
index 0000000000..7869e7f57a
--- /dev/null
+++ b/changelog.d/6746.feature
@@ -0,0 +1 @@
+[Notification] - Handle creation of notification for live location and poll start
diff --git a/changelog.d/6749.wip b/changelog.d/6749.wip
new file mode 100644
index 0000000000..d7fac1efc1
--- /dev/null
+++ b/changelog.d/6749.wip
@@ -0,0 +1 @@
+Adds space list bottom sheet for new app layout
diff --git a/changelog.d/6783.misc b/changelog.d/6783.misc
new file mode 100644
index 0000000000..d1095c1203
--- /dev/null
+++ b/changelog.d/6783.misc
@@ -0,0 +1 @@
+Decouples the variant logic from the vector module
diff --git a/changelog.d/6786.misc b/changelog.d/6786.misc
new file mode 100644
index 0000000000..a916336ae4
--- /dev/null
+++ b/changelog.d/6786.misc
@@ -0,0 +1 @@
+Add a developer setting to enable LeakCanary at runtime
diff --git a/changelog.d/6795.wip b/changelog.d/6795.wip
new file mode 100644
index 0000000000..da525a2c67
--- /dev/null
+++ b/changelog.d/6795.wip
@@ -0,0 +1 @@
+Makes toolbar switch title based on space in New App Layout
diff --git a/changelog.d/6798.wip b/changelog.d/6798.wip
new file mode 100644
index 0000000000..a16270666b
--- /dev/null
+++ b/changelog.d/6798.wip
@@ -0,0 +1 @@
+[Devices management] Add a feature flag and empty screen for future new layout
diff --git a/changelog.d/6799.misc b/changelog.d/6799.misc
new file mode 100644
index 0000000000..b756c2c07b
--- /dev/null
+++ b/changelog.d/6799.misc
@@ -0,0 +1 @@
+[Create Room] Reduce some boilerplate with room state event contents
diff --git a/changelog.d/6806.wip b/changelog.d/6806.wip
new file mode 100644
index 0000000000..9b00139c62
--- /dev/null
+++ b/changelog.d/6806.wip
@@ -0,0 +1 @@
+[Devices management] Other sessions section in new layout
diff --git a/changelog.d/6808.misc b/changelog.d/6808.misc
new file mode 100644
index 0000000000..06eeff862b
--- /dev/null
+++ b/changelog.d/6808.misc
@@ -0,0 +1 @@
+[Call] Memory leak after a call
diff --git a/changelog.d/6843.misc b/changelog.d/6843.misc
new file mode 100644
index 0000000000..5382e27082
--- /dev/null
+++ b/changelog.d/6843.misc
@@ -0,0 +1 @@
+Fix some string template
diff --git a/coverage.gradle b/coverage.gradle
index fb2352f47f..f335ed8063 100644
--- a/coverage.gradle
+++ b/coverage.gradle
@@ -1,12 +1,37 @@
-def excludes = [ ]
+def excludes = [
+// dependency injection graph
+'**/*Module.*',
+'**/*Module*.*',
+
+// Framework entry points
+'**/*Activity*',
+'**/*Fragment*',
+'**/*Application*',
+'**/*AndroidService*',
+
+// We would like to exclude android widgets as well but our naming is inconsistent
+
+// Proof of concept
+'**/*Login2*',
+
+// Generated
+'**/*JsonAdapter*',
+'**/*Item.*',
+'**/*$Holder.*',
+'**/*ViewHolder.*',
+'**/*View.*',
+'**/*BottomSheet.*'
+]
def initializeReport(report, projects, classExcludes) {
projects.each { project -> project.apply plugin: 'jacoco' }
- report.executionData { fileTree(rootProject.rootDir.absolutePath).include(
- "**/build/outputs/unit_test_code_coverage/**/*.exec",
- "**/build/outputs/code_coverage/**/coverage.ec"
- ) }
+ report.executionData {
+ fileTree(rootProject.rootDir.absolutePath).include(
+ "**/build/**/*.exec",
+ "**/build/outputs/code_coverage/**/coverage.ec",
+ )
+ }
report.reports {
xml.enabled true
html.enabled true
@@ -21,13 +46,11 @@ def initializeReport(report, projects, classExcludes) {
switch (project) {
case { project.plugins.hasPlugin("com.android.application") }:
androidClassDirs.add("${project.buildDir}/tmp/kotlin-classes/gplayDebug")
- androidSourceDirs.add("${project.buildDir}/generated/source/kapt/gplayDebug")
androidSourceDirs.add("${project.projectDir}/src/main/kotlin")
androidSourceDirs.add("${project.projectDir}/src/main/java")
break
case { project.plugins.hasPlugin("com.android.library") }:
androidClassDirs.add("${project.buildDir}/tmp/kotlin-classes/debug")
- androidSourceDirs.add("${project.buildDir}/generated/source/kapt/debug")
androidSourceDirs.add("${project.projectDir}/src/main/kotlin")
androidSourceDirs.add("${project.projectDir}/src/main/java")
break
@@ -48,17 +71,21 @@ def collectProjects(predicate) {
return subprojects.findAll { it.buildFile.isFile() && predicate(it) }
}
-task theCodeCoverageReport(type: JacocoReport) {
+task generateCoverageReport(type: JacocoReport) {
outputs.upToDateWhen { false }
rootProject.apply plugin: 'jacoco'
- tasks.withType(Test) {
- jacoco.includeNoLocationClasses = true
- }
- def projects = collectProjects { ['vector','matrix-sdk-android'].contains(it.name) }
- dependsOn {
- [':matrix-sdk-android:testDebugUnitTest'] +
- [':vector:testGplayDebugUnitTest'] +
- [':matrix-sdk-android:connectedDebugAndroidTest']
- }
+ def projects = collectProjects { ['vector', 'matrix-sdk-android'].contains(it.name) }
initializeReport(it, projects, excludes)
}
+
+task unitTestsWithCoverage(type: GradleBuild) {
+ // the 7.1.3 android gradle plugin has a bug where enableTestCoverage generates invalid coverage
+ startParameter.projectProperties.coverage = [enableTestCoverage: false]
+ tasks = [':vector:testGplayDebugUnitTest', ':matrix-sdk-android:testDebugUnitTest']
+}
+
+task instrumentationTestsWithCoverage(type: GradleBuild) {
+ startParameter.projectProperties.coverage = [enableTestCoverage: true]
+ startParameter.projectProperties['android.testInstrumentationRunnerArguments.notPackage'] = 'im.vector.app.ui'
+ tasks = [':vector:connectedGplayDebugAndroidTest', 'matrix-sdk-android:connectedDebugAndroidTest']
+}
diff --git a/dependencies.gradle b/dependencies.gradle
index 451ad4449b..93a62a548e 100644
--- a/dependencies.gradle
+++ b/dependencies.gradle
@@ -13,28 +13,30 @@ ext.versions = [
def gradle = "7.1.3"
// Ref: https://kotlinlang.org/releases.html
def kotlin = "1.6.21"
-def kotlinCoroutines = "1.6.2"
+def kotlinCoroutines = "1.6.4"
def dagger = "2.42"
+def appDistribution = "16.0.0-beta03"
def retrofit = "2.9.0"
def arrow = "0.8.2"
def markwon = "4.6.2"
def moshi = "1.13.0"
-def lifecycle = "2.4.1"
+def lifecycle = "2.5.1"
def flowBinding = "1.2.0"
+def flipper = "0.156.0"
def epoxy = "4.6.2"
-def mavericks = "2.6.1"
+def mavericks = "2.7.0"
def glide = "4.13.2"
def bigImageViewer = "1.8.1"
def jjwt = "0.11.5"
def vanniktechEmoji = "0.15.0"
+def fragment = "1.5.1"
+
// Testing
-def mockk = "1.12.4"
+def mockk = "1.12.3" // We need to use 1.12.3 to have mocking in androidTest until a new version is released: https://github.com/mockk/mockk/issues/819
def espresso = "3.4.0"
def androidxTest = "1.4.0"
def androidxOrchestrator = "1.4.1"
-
-
ext.libs = [
gradle : [
'gradlePlugin' : "com.android.tools.build:gradle:$gradle",
@@ -48,12 +50,14 @@ ext.libs = [
'coroutinesTest' : "org.jetbrains.kotlinx:kotlinx-coroutines-test:$kotlinCoroutines"
],
androidx : [
- 'activity' : "androidx.activity:activity:1.4.0",
+ 'activity' : "androidx.activity:activity:1.5.1",
'appCompat' : "androidx.appcompat:appcompat:1.4.2",
+ 'biometric' : "androidx.biometric:biometric:1.1.0",
'core' : "androidx.core:core-ktx:1.8.0",
'recyclerview' : "androidx.recyclerview:recyclerview:1.2.1",
'exifinterface' : "androidx.exifinterface:exifinterface:1.3.3",
- 'fragmentKtx' : "androidx.fragment:fragment-ktx:1.4.1",
+ 'fragmentKtx' : "androidx.fragment:fragment-ktx:$fragment",
+ 'fragmentTesting' : "androidx.fragment:fragment-testing:$fragment",
'constraintLayout' : "androidx.constraintlayout:constraintlayout:2.1.4",
'work' : "androidx.work:work-runtime-ktx:2.7.1",
'autoFill' : "androidx.autofill:autofill:1.1.0",
@@ -78,16 +82,27 @@ ext.libs = [
'transition' : "androidx.transition:transition:1.2.0",
],
google : [
- 'material' : "com.google.android.material:material:1.6.1"
+ 'material' : "com.google.android.material:material:1.6.1",
+ 'appdistributionApi' : "com.google.firebase:firebase-appdistribution-api-ktx:$appDistribution",
+ 'appdistribution' : "com.google.firebase:firebase-appdistribution:$appDistribution",
],
dagger : [
'dagger' : "com.google.dagger:dagger:$dagger",
'daggerCompiler' : "com.google.dagger:dagger-compiler:$dagger",
'hilt' : "com.google.dagger:hilt-android:$dagger",
+ 'hiltAndroidTesting' : "com.google.dagger:hilt-android-testing:$dagger",
'hiltCompiler' : "com.google.dagger:hilt-compiler:$dagger"
],
+ flipper : [
+ 'flipper' : "com.facebook.flipper:flipper:$flipper",
+ 'flipperNetworkPlugin' : "com.facebook.flipper:flipper-network-plugin:$flipper",
+ ],
+ element : [
+ 'opusencoder' : "io.element.android:opusencoder:1.0.4",
+ ],
squareup : [
'moshi' : "com.squareup.moshi:moshi:$moshi",
+ 'moshiKt' : "com.squareup.moshi:moshi-kotlin:$moshi",
'moshiKotlin' : "com.squareup.moshi:moshi-kotlin-codegen:$moshi",
'retrofit' : "com.squareup.retrofit2:retrofit:$retrofit",
'retrofitMoshi' : "com.squareup.retrofit2:converter-moshi:$retrofit"
@@ -153,3 +168,5 @@ ext.libs = [
'junit' : "junit:junit:4.13.2"
]
]
+
+
diff --git a/dependencies_groups.gradle b/dependencies_groups.gradle
index 59cefe7e89..bcd737acc9 100644
--- a/dependencies_groups.gradle
+++ b/dependencies_groups.gradle
@@ -9,6 +9,7 @@ ext.groups = [
'com.github.jetradarmobile',
'com.github.MatrixFrog',
'com.github.tapadoo',
+ 'com.github.UnifiedPush',
'com.github.vector-im',
'com.github.yalantis',
'com.github.Zhuinden',
@@ -31,6 +32,7 @@ ext.groups = [
],
group: [
'com.android',
+ 'com.android.ndk.thirdparty',
'com.android.tools',
'com.google.firebase',
'com.google.testing.platform',
@@ -52,6 +54,7 @@ ext.groups = [
'com.dropbox.core',
'com.soywiz.korlibs.korte',
'com.facebook.fbjni',
+ 'com.facebook.flipper',
'com.facebook.fresco',
'com.facebook.infer.annotation',
'com.facebook.soloader',
@@ -71,6 +74,7 @@ ext.groups = [
'com.github.javaparser',
'com.github.piasy',
'com.github.shyiko.klob',
+ 'com.github.rubensousa',
'com.google',
'com.google.android',
'com.google.api.grpc',
@@ -93,6 +97,7 @@ ext.groups = [
'com.ibm.icu',
'com.jakewharton.android.repackaged',
'com.jakewharton.timber',
+ 'com.kgurgul.flipper',
'com.linkedin.dexmaker',
'com.mapbox.mapboxsdk',
'com.nulab-inc',
@@ -102,7 +107,9 @@ ext.groups = [
'com.pinterest.ktlint',
'com.posthog.android',
'com.squareup',
+ 'com.squareup.curtains',
'com.squareup.duktape',
+ 'com.squareup.leakcanary',
'com.squareup.moshi',
'com.squareup.okhttp3',
'com.squareup.okio',
@@ -120,6 +127,8 @@ ext.groups = [
'commons-logging',
'info.picocli',
'io.arrow-kt',
+ 'io.element.android',
+ 'io.github.davidburstrom.contester',
'io.github.detekt.sarif4k',
'io.github.microutils',
'io.github.reactivecircus.flowbinding',
@@ -168,6 +177,7 @@ ext.groups = [
'org.glassfish.jaxb',
'org.hamcrest',
'org.jacoco',
+ 'org.java-websocket',
'org.jetbrains',
'org.jetbrains.dokka',
'org.jetbrains.intellij.deps',
diff --git a/docs/danger.md b/docs/danger.md
new file mode 100644
index 0000000000..afa3555469
--- /dev/null
+++ b/docs/danger.md
@@ -0,0 +1,105 @@
+## Danger
+
+
+
+* [What does danger checks](#what-does-danger-checks)
+ * [PR check](#pr-check)
+ * [Quality check](#quality-check)
+* [Setup](#setup)
+* [Run danger locally](#run-danger-locally)
+* [Danger user](#danger-user)
+* [Useful links](#useful-links)
+
+
+
+## What does danger checks
+
+### PR check
+
+See the [dangerfile](../tools/danger/dangerfile.js). If you add rules in the dangerfile, please update the list below!
+
+Here are the checks that Danger does so far:
+
+- PR description is not empty
+- Big PR got a warning to recommend to split
+- PR contains a file for towncrier and extension is checked
+- PR does not modify frozen classes
+- PR contains a Sign-Off, with exception for Element employee contributors
+- PR with change on layout should include screenshot in the description
+- PR which adds png file warn about the usage of vector drawables
+- non draft PR should have a reviewer
+
+### Quality check
+
+After all the checks that generate checkstyle XML report, such as Ktlint, lint, or Detekt, Danger is run with this [dangerfile](../tools/danger/dangerfile-lint.js), in order to post comments to the PR with the detected error and warnings.
+
+To run locally, you will have to install the plugin `danger-plugin-lint-report` using:
+
+```shell
+yarn add danger-plugin-lint-report --dev
+```
+
+## Setup
+
+This operation should not be necessary, since Danger is already setup for the project.
+
+To setup danger to the project, run:
+
+```shell
+bundle exec danger init
+```
+
+## Run danger locally
+
+When modifying the [dangerfile](../tools/danger/dangerfile.js), you can check it by running Danger locally.
+
+To run danger locally, install it and run:
+
+```shell
+bundle exec danger pr --dangerfile=./tools/danger/dangerfile.js
+```
+
+For instance:
+
+```shell
+bundle exec danger pr https://github.com/vector-im/element-android/pull/6637 --dangerfile=./tools/danger/dangerfile.js
+```
+
+We may need to create a GitHub token to have less API rate limiting, and then set the env var:
+
+```shell
+export DANGER_GITHUB_API_TOKEN='YOUR_TOKEN'
+```
+
+Swift and Kotlin (just in case)
+
+```shell
+bundle exec danger-swift pr --dangerfile=./tools/danger/dangerfile.js
+bundle exec danger-kotlin pr --dangerfile=./tools/danger/dangerfile.js
+```
+
+## Danger user
+
+To let Danger check all the PRs, including PRs form forks, a GitHub account have been created:
+- login: ElementBot
+- password: Stored on Passbolt
+- GitHub token: A token with limited access has been created and added to the repository https://github.com/vector-im/element-android as secret DANGER_GITHUB_API_TOKEN. This token is not saved anywhere else. In case of problem, just delete it and create a new one, then update the secret.
+
+PRs from forks do not always have access to the secret `secrets.DANGER_GITHUB_API_TOKEN`, so `secrets.GITHUB_TOKEN` is also provided to the job environment. If `secrets.DANGER_GITHUB_API_TOKEN` is available, it will be used, so user `ElementBot` will comment the PR. Else `secrets.GITHUB_TOKEN` will be used, and bot `github-actions` will comment the PR.
+
+## Useful links
+
+- https://danger.systems/
+- https://danger.systems/js/
+- https://danger.systems/js/guides/getting_started.html
+- https://danger.systems/js/reference.html
+- https://github.com/danger/awesome-danger
+
+Some danger files to get inspired from
+
+- https://github.com/artsy/emission/blob/master/dangerfile.ts
+- https://github.com/facebook/react-native/blob/master/bots/dangerfile.js
+- https://github.com/apollographql/apollo-client/blob/master/config/dangerfile.ts
+- https://github.com/styleguidist/react-styleguidist/blob/master/dangerfile.js
+- https://github.com/storybooks/storybook/blob/master/dangerfile.js
+- https://github.com/ReactiveX/rxjs/blob/master/dangerfile.js
diff --git a/docs/flipper.md b/docs/flipper.md
new file mode 100644
index 0000000000..495425ce5f
--- /dev/null
+++ b/docs/flipper.md
@@ -0,0 +1,58 @@
+# Flipper
+
+
+
+* [Introduction](#introduction)
+* [Setup](#setup)
+ * [Troubleshoot](#troubleshoot)
+ * [No device found issue](#no-device-found-issue)
+ * [Diagnostic Activity](#diagnostic-activity)
+ * [Other](#other)
+* [Links](#links)
+
+
+
+## Introduction
+
+[Flipper](https://fbflipper.com) is a powerful tool from Meta, which allow to inspect the running application details and states from your computer.
+
+Flipper is configured in the Element Android project to let the developers be able to:
+- inspect all the Realm databases content;
+- do layout inspection;
+- see the crash logs;
+- see the logcat;
+- see all the network requests;
+- see all the SharedPreferences;
+- take screenshots and record videos of the device;
+- and more!
+
+## Setup
+
+- Install Flipper on your computer. Follow instructions here: https://fbflipper.com/docs/getting-started/index/
+- Run the debug version of Element on an emulator or on a real device.
+
+### Troubleshoot
+
+#### No device found issue
+
+The configuration of the Flipper application has to be updated. The issue has been asked and answered here: https://stackoverflow.com/questions/71744103/android-emulator-unable-to-connect-to-flipper/72608113#72608113
+
+#### Diagnostic Activity
+
+Flipper comes with a Diagnostic Activity that you can start from command line using:
+
+```shell
+adb shell am start -n im.vector.app.debug/com.facebook.flipper.android.diagnostics.FlipperDiagnosticActivity
+```
+
+It provides some log which can help to figure out what's going on client side.
+
+#### Other
+
+https://fbflipper.com/docs/getting-started/troubleshooting/android/ may help.
+
+## Links
+
+- Official Flipper website: https://fbflipper.com
+- Realm Plugin for Flipper: https://github.com/kamgurgul/Flipper-Realm
+- Dedicated Matrix room: https://matrix.to/#/#unifiedpush:matrix.org
diff --git a/docs/nightly_build.md b/docs/nightly_build.md
new file mode 100644
index 0000000000..7750e0466a
--- /dev/null
+++ b/docs/nightly_build.md
@@ -0,0 +1,54 @@
+# Nightly builds
+
+
+
+* [Configuration](#configuration)
+* [How to register to get nightly build](#how-to-register-to-get-nightly-build)
+* [Build nightly manually](#build-nightly-manually)
+
+
+
+## Configuration
+
+The nightly build will contain what's on develop, in release mode, for Gplay variant. It is signed using a dedicated signature, and has a dedicated appId (`im.vector.app.nightly`), so it can be installed along with the production version of Element Android. The only other difference compared to Element Android is a different app icon background. We do not want to change the app name since it will also affect some strings in the app, and we do want to do that.
+
+Nightly builds are built and released to Firebase every days, and automatically.
+
+This is recommended to exclusively use this app, with your main account, instead of Element Android, and fallback to Element Android just in case of regression, to discover as soon as possible any regression, and report it to the team. To avoid double notification, you may want to disable the notification from the Element Android production version. Just open Element Android, navigate to `Settings/Notifications` and uncheck `Enable notifications for this session`.
+
+*Note:* Due to a limitation of Firebase, the nightly build is the universal build, which means that the size of the APK is a bit bigger, but this should not have any other side effect.
+
+## How to register to get nightly build
+
+Provide your email to the Android team, who will add it to the list "External testers" on Firebase. You will then receive an invite on the provided email.
+
+Follow the instructions on the email to install the latest nightly build. This is not clear yet if new nightly build will be automatically installed or not.
+
+## Build nightly manually
+
+Nightly build can be built manually from your computer. You will need to retrieved some secrets from Passbolt and add them to your file `~/.gradle/gradle.properties`:
+
+```
+signing.element.nightly.storePassword=VALUE_FROM_PASSBOLT
+signing.element.nightly.keyId=VALUE_FROM_PASSBOLT
+signing.element.nightly.keyPassword=VALUE_FROM_PASSBOLT
+```
+
+You will also need to add the environment variable `FIREBASE_TOKEN`:
+
+```sh
+export FIREBASE_TOKEN=VALUE_FROM_PASSBOLT
+```
+
+Then you can run the following commands (which are also used in the file for [the GitHub action](../.github/workflows/nightly.yml)):
+
+```sh
+git checkout develop
+mv towncrier.toml towncrier.toml.bak
+sed 's/CHANGES\.md/CHANGES_NIGHTLY\.md/' towncrier.toml.bak > towncrier.toml
+rm towncrier.toml.bak
+yes n | towncrier --version nightly
+./gradlew assembleGplayNightly appDistributionUploadGplayNightly $CI_GRADLE_ARG_PROPERTIES
+```
+
+Then you can reset the change on the codebase.
diff --git a/docs/pull_request.md b/docs/pull_request.md
index d2d2bb7a3b..7f6ac86b8a 100644
--- a/docs/pull_request.md
+++ b/docs/pull_request.md
@@ -83,15 +83,16 @@ Exceptions can occur:
##### PR Review Assignment
-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:
+We use automatic assignment for PR reviews. **A PR is automatically routed by GitHub to one team member** using the round robin algorithm. Additional reviewers can be used for complex changes or when the first reviewer is not confident enough on the changes.
+The process is the following:
-- 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.
+- The PR creator selects the [element-android-reviewers](https://github.com/orgs/vector-im/teams/element-android-reviewers) team as a reviewer.
+- GitHub automatically assign the reviewer. If the reviewer is not available (holiday, etc.), remove them and set again the team, GitHub will select another reviewer.
+- Alternatively, the PR creator can directly assign specific people if they have another Android developer in their team or they think a specific reviewer should take a look at their PR.
- 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-reviewers](https://github.com/orgs/vector-im/teams/element-android-reviewers) or any members 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 member directly.
##### PR review time
@@ -102,6 +103,7 @@ Some tips to achieve it:
- Set up your GH notifications correctly
- Check your pulls page: [https://github.com/pulls](https://github.com/pulls)
- Check your pending assigned PRs before starting or resuming your day to day tasks
+- If you are busy with high priority tasks, inform the author. They will find another developer
It is hard to define a deadline for a review. It depends on the PR size and the complexity. Let's start with a goal of 24h (working day!) for a PR smaller than 500 lines. If bigger, the submitter and the reviewer should discuss.
@@ -189,7 +191,7 @@ Examples of prefixes:
- `[Bugfix]`
- etc.
-Also, it's still possible to add labels to the PRs, such as `A-` or `T-` labels, even if this is not a string requirement. We prefer to spend time to add labels on issues.
+Also, it's still possible to add labels to the PRs, such as `A-` or `T-` labels, even if this is not a strong requirement. We prefer to spend time to add labels on issues.
##### PR description
diff --git a/docs/unifiedpush.md b/docs/unifiedpush.md
new file mode 100644
index 0000000000..2851644e66
--- /dev/null
+++ b/docs/unifiedpush.md
@@ -0,0 +1,58 @@
+# UnifiedPush
+
+
+
+* [Introduction](#introduction)
+* [Configuration in Element-Android and their forks](#configuration-in-element-android-and-their-forks)
+ * [Enabling and disabling the feature](#enabling-and-disabling-the-feature)
+ * [Override the configuration at runtime](#override-the-configuration-at-runtime)
+ * [Enabling the feature](#enabling-the-feature)
+ * [Disabling the feature](#disabling-the-feature)
+ * [Useful links](#useful-links)
+
+
+
+## Introduction
+
+The recently started UnifiedPush project is an Android protocol and library for apps to be able to receive distributor-agnostic push notifications.
+
+The *F-Droid* and *Gplay* flavors of Element Android support UnifiedPush, so the user can use any distributor installed on their devices. This would make it possible to have push notifications without depending on Google services or libraries. Currently, the main distributors are [ntfy](https://ntfy.sh) which does not require any setup (like manual registration) to use the public server and [NextPush](https://github.com/UP-NextPush/android), available as a nextcloud application.
+
+The *Gplay* variant uses a UnifiedPush library which basically embed a FCM distributor built into the application (so a user doesn't need to do anything other than install the app to get FCM notifications). This variant uses Google Services to receive notifications if the user has not installed any distributor.
+
+The *F-Droid* variant does not use this library to avoid any proprietary blob. It will use a polling service if the user has not installed any distributor.
+
+In all cases, if there are other distributors available, the user will have to opt-in to one of them in the preferences.
+
+## Configuration in Element-Android and their forks
+
+### Enabling and disabling the feature
+
+Allowing the user to use an alternative distributor can be changed in [Config](../vector-config/src/main/java/im/vector/app/config/Config.kt). The flag is named `ALLOW_EXTERNAL_UNIFIED_PUSH_DISTRIBUTORS`. Default value is `true`.
+
+#### Override the configuration at runtime
+
+On debug version, it is possible to override this configuration at runtime, using the `Feature` screen. The Feature is named `Allow external UnifiedPush distributors`.
+
+#### Enabling the feature
+
+This is the default behavior of Element Android.
+
+If `ALLOW_EXTERNAL_UNIFIED_PUSH_DISTRIBUTORS` is set to true, it allows any available external UnifiedPush distributor to be chosen by the user.
+- For Gplay variant it means that FCM will be used by default, but user can choose another UnifiedPush distributor;
+- For F-Droid variant, it means that background polling will be used by default, but user can choose another UnifiedPush distributor.
+- On the UI, the setting to choose an alternative distributor will be visible to the user, and some tests in the notification troubleshoot screen will shown.
+- For F-Droid, if the user has chosen a distributor, the settings to configure the background polling will be hidden.
+
+#### Disabling the feature
+
+If `ALLOW_EXTERNAL_UNIFIED_PUSH_DISTRIBUTORS` is set to false, it prevents the usage of external UnifiedPush distributors.
+- For Gplay variant it means that only FCM will be used;
+- For F-Droid variant, it means that only background polling will be used.
+- On the UI, the setting to choose an alternative distributor will be hidden to the user, and some tests in the notification troubleshoot screen will be hidden.
+
+### Useful links
+
+- UnifiedPush official website: [https://unifiedpush.org/](https://unifiedpush.org/)
+- List of available distributors can be retrieved here: [https://unifiedpush.org/users/distributors/](https://unifiedpush.org/users/distributors/)
+- UnifiedPush project discussion can occurs here: [#unifiedpush:matrix.org](https://matrix.to/#/#unifiedpush:matrix.org)
diff --git a/fastlane/metadata/android/ar/short_description.txt b/fastlane/metadata/android/ar/short_description.txt
index 48df6f2b0c..2b0789b376 100644
--- a/fastlane/metadata/android/ar/short_description.txt
+++ b/fastlane/metadata/android/ar/short_description.txt
@@ -1 +1 @@
-مُحادثة آمنة لا مركزية و VoIP. حافظ على بياناتك آمنة من الأطراف الثالثة.
+برنامج المراسلة الجماعية - الرسائل المشفرة والدردشة الجماعية ومكالمات الفيديو
diff --git a/fastlane/metadata/android/ar/title.txt b/fastlane/metadata/android/ar/title.txt
index 11992d355d..c2ac1b2876 100644
--- a/fastlane/metadata/android/ar/title.txt
+++ b/fastlane/metadata/android/ar/title.txt
@@ -1 +1 @@
-Element (Riot.im سابقًا)
+إيليمنت - تطبيق محادثات أمن
diff --git a/fastlane/metadata/android/cs-CZ/changelogs/40104160.txt b/fastlane/metadata/android/cs-CZ/changelogs/40104160.txt
new file mode 100644
index 0000000000..922d4dc76b
--- /dev/null
+++ b/fastlane/metadata/android/cs-CZ/changelogs/40104160.txt
@@ -0,0 +1,2 @@
+Hlavní změny v této verzi: Vylepšena správa šifrovaných zpráv. Opravy různých chyb a vylepšení stability.
+Úplný seznam změn: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/cs-CZ/changelogs/40104180.txt b/fastlane/metadata/android/cs-CZ/changelogs/40104180.txt
new file mode 100644
index 0000000000..578549ce6c
--- /dev/null
+++ b/fastlane/metadata/android/cs-CZ/changelogs/40104180.txt
@@ -0,0 +1,2 @@
+Hlavní změny v této verzi: Opravy různých chyb a vylepšení stability.
+Úplný seznam změn: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/cs-CZ/changelogs/40104190.txt b/fastlane/metadata/android/cs-CZ/changelogs/40104190.txt
new file mode 100644
index 0000000000..578549ce6c
--- /dev/null
+++ b/fastlane/metadata/android/cs-CZ/changelogs/40104190.txt
@@ -0,0 +1,2 @@
+Hlavní změny v této verzi: Opravy různých chyb a vylepšení stability.
+Úplný seznam změn: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/cs-CZ/changelogs/40104200.txt b/fastlane/metadata/android/cs-CZ/changelogs/40104200.txt
new file mode 100644
index 0000000000..578549ce6c
--- /dev/null
+++ b/fastlane/metadata/android/cs-CZ/changelogs/40104200.txt
@@ -0,0 +1,2 @@
+Hlavní změny v této verzi: Opravy různých chyb a vylepšení stability.
+Úplný seznam změn: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/cs-CZ/changelogs/40104220.txt b/fastlane/metadata/android/cs-CZ/changelogs/40104220.txt
new file mode 100644
index 0000000000..578549ce6c
--- /dev/null
+++ b/fastlane/metadata/android/cs-CZ/changelogs/40104220.txt
@@ -0,0 +1,2 @@
+Hlavní změny v této verzi: Opravy různých chyb a vylepšení stability.
+Úplný seznam změn: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/cs-CZ/changelogs/40104230.txt b/fastlane/metadata/android/cs-CZ/changelogs/40104230.txt
new file mode 100644
index 0000000000..578549ce6c
--- /dev/null
+++ b/fastlane/metadata/android/cs-CZ/changelogs/40104230.txt
@@ -0,0 +1,2 @@
+Hlavní změny v této verzi: Opravy různých chyb a vylepšení stability.
+Úplný seznam změn: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/cs-CZ/changelogs/40104240.txt b/fastlane/metadata/android/cs-CZ/changelogs/40104240.txt
new file mode 100644
index 0000000000..578549ce6c
--- /dev/null
+++ b/fastlane/metadata/android/cs-CZ/changelogs/40104240.txt
@@ -0,0 +1,2 @@
+Hlavní změny v této verzi: Opravy různých chyb a vylepšení stability.
+Úplný seznam změn: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/cs-CZ/changelogs/40104250.txt b/fastlane/metadata/android/cs-CZ/changelogs/40104250.txt
new file mode 100644
index 0000000000..578549ce6c
--- /dev/null
+++ b/fastlane/metadata/android/cs-CZ/changelogs/40104250.txt
@@ -0,0 +1,2 @@
+Hlavní změny v této verzi: Opravy různých chyb a vylepšení stability.
+Úplný seznam změn: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/cs-CZ/changelogs/40104260.txt b/fastlane/metadata/android/cs-CZ/changelogs/40104260.txt
new file mode 100644
index 0000000000..721c24555b
--- /dev/null
+++ b/fastlane/metadata/android/cs-CZ/changelogs/40104260.txt
@@ -0,0 +1,2 @@
+Hlavní změny v této verzi: Podpora UnifiedPush a možnost používat push bez FCM.
+Úplný seznam změn: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/cs-CZ/changelogs/40104270.txt b/fastlane/metadata/android/cs-CZ/changelogs/40104270.txt
new file mode 100644
index 0000000000..578549ce6c
--- /dev/null
+++ b/fastlane/metadata/android/cs-CZ/changelogs/40104270.txt
@@ -0,0 +1,2 @@
+Hlavní změny v této verzi: Opravy různých chyb a vylepšení stability.
+Úplný seznam změn: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/cs-CZ/changelogs/40104280.txt b/fastlane/metadata/android/cs-CZ/changelogs/40104280.txt
new file mode 100644
index 0000000000..578549ce6c
--- /dev/null
+++ b/fastlane/metadata/android/cs-CZ/changelogs/40104280.txt
@@ -0,0 +1,2 @@
+Hlavní změny v této verzi: Opravy různých chyb a vylepšení stability.
+Úplný seznam změn: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/de-DE/changelogs/40104140.txt b/fastlane/metadata/android/de-DE/changelogs/40104140.txt
new file mode 100644
index 0000000000..3915434ee0
--- /dev/null
+++ b/fastlane/metadata/android/de-DE/changelogs/40104140.txt
@@ -0,0 +1,2 @@
+Die wichtigsten Änderungen in dieser Version: Verbesserte Verwaltung der ignorierten Benutzer:innen. Verschiedene Fehlerbehebungen und Stabilitätsverbesserungen.
+Vollständiges Änderungsprotokoll: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/de-DE/changelogs/40104160.txt b/fastlane/metadata/android/de-DE/changelogs/40104160.txt
new file mode 100644
index 0000000000..cdf06e217a
--- /dev/null
+++ b/fastlane/metadata/android/de-DE/changelogs/40104160.txt
@@ -0,0 +1,2 @@
+Die wichtigsten Änderungen in dieser Version: Bessere Verwaltung von verschlüsselten Nachrichten. Verschiedene Fehlerbehebungen und Stabilitätsverbesserungen.
+Vollständiges Änderungsprotokoll: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/de-DE/changelogs/40104180.txt b/fastlane/metadata/android/de-DE/changelogs/40104180.txt
new file mode 100644
index 0000000000..50b5647608
--- /dev/null
+++ b/fastlane/metadata/android/de-DE/changelogs/40104180.txt
@@ -0,0 +1,2 @@
+Die wichtigsten Änderungen in dieser Version: Verschiedene Fehlerbehebungen und Stabilitätsverbesserungen.
+Vollständiges Änderungsprotokoll: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/de-DE/changelogs/40104190.txt b/fastlane/metadata/android/de-DE/changelogs/40104190.txt
new file mode 100644
index 0000000000..50b5647608
--- /dev/null
+++ b/fastlane/metadata/android/de-DE/changelogs/40104190.txt
@@ -0,0 +1,2 @@
+Die wichtigsten Änderungen in dieser Version: Verschiedene Fehlerbehebungen und Stabilitätsverbesserungen.
+Vollständiges Änderungsprotokoll: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/de-DE/changelogs/40104200.txt b/fastlane/metadata/android/de-DE/changelogs/40104200.txt
new file mode 100644
index 0000000000..50b5647608
--- /dev/null
+++ b/fastlane/metadata/android/de-DE/changelogs/40104200.txt
@@ -0,0 +1,2 @@
+Die wichtigsten Änderungen in dieser Version: Verschiedene Fehlerbehebungen und Stabilitätsverbesserungen.
+Vollständiges Änderungsprotokoll: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/de-DE/changelogs/40104220.txt b/fastlane/metadata/android/de-DE/changelogs/40104220.txt
new file mode 100644
index 0000000000..50b5647608
--- /dev/null
+++ b/fastlane/metadata/android/de-DE/changelogs/40104220.txt
@@ -0,0 +1,2 @@
+Die wichtigsten Änderungen in dieser Version: Verschiedene Fehlerbehebungen und Stabilitätsverbesserungen.
+Vollständiges Änderungsprotokoll: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/de-DE/changelogs/40104230.txt b/fastlane/metadata/android/de-DE/changelogs/40104230.txt
new file mode 100644
index 0000000000..50b5647608
--- /dev/null
+++ b/fastlane/metadata/android/de-DE/changelogs/40104230.txt
@@ -0,0 +1,2 @@
+Die wichtigsten Änderungen in dieser Version: Verschiedene Fehlerbehebungen und Stabilitätsverbesserungen.
+Vollständiges Änderungsprotokoll: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/de-DE/changelogs/40104240.txt b/fastlane/metadata/android/de-DE/changelogs/40104240.txt
new file mode 100644
index 0000000000..50b5647608
--- /dev/null
+++ b/fastlane/metadata/android/de-DE/changelogs/40104240.txt
@@ -0,0 +1,2 @@
+Die wichtigsten Änderungen in dieser Version: Verschiedene Fehlerbehebungen und Stabilitätsverbesserungen.
+Vollständiges Änderungsprotokoll: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/de-DE/changelogs/40104250.txt b/fastlane/metadata/android/de-DE/changelogs/40104250.txt
new file mode 100644
index 0000000000..50b5647608
--- /dev/null
+++ b/fastlane/metadata/android/de-DE/changelogs/40104250.txt
@@ -0,0 +1,2 @@
+Die wichtigsten Änderungen in dieser Version: Verschiedene Fehlerbehebungen und Stabilitätsverbesserungen.
+Vollständiges Änderungsprotokoll: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/en-US/changelogs/40104200.txt b/fastlane/metadata/android/en-US/changelogs/40104200.txt
new file mode 100644
index 0000000000..61db61727a
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/40104200.txt
@@ -0,0 +1,2 @@
+Main changes in this version: Various bug fixes and stability improvements.
+Full changelog: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/en-US/changelogs/40104220.txt b/fastlane/metadata/android/en-US/changelogs/40104220.txt
new file mode 100644
index 0000000000..61db61727a
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/40104220.txt
@@ -0,0 +1,2 @@
+Main changes in this version: Various bug fixes and stability improvements.
+Full changelog: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/en-US/changelogs/40104230.txt b/fastlane/metadata/android/en-US/changelogs/40104230.txt
new file mode 100644
index 0000000000..61db61727a
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/40104230.txt
@@ -0,0 +1,2 @@
+Main changes in this version: Various bug fixes and stability improvements.
+Full changelog: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/en-US/changelogs/40104240.txt b/fastlane/metadata/android/en-US/changelogs/40104240.txt
new file mode 100644
index 0000000000..61db61727a
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/40104240.txt
@@ -0,0 +1,2 @@
+Main changes in this version: Various bug fixes and stability improvements.
+Full changelog: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/en-US/changelogs/40104250.txt b/fastlane/metadata/android/en-US/changelogs/40104250.txt
new file mode 100644
index 0000000000..61db61727a
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/40104250.txt
@@ -0,0 +1,2 @@
+Main changes in this version: Various bug fixes and stability improvements.
+Full changelog: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/en-US/changelogs/40104260.txt b/fastlane/metadata/android/en-US/changelogs/40104260.txt
new file mode 100644
index 0000000000..8808866c5d
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/40104260.txt
@@ -0,0 +1,2 @@
+Main changes in this version: Use UnifiedPush and allows user to have push without FCM.
+Full changelog: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/en-US/changelogs/40104270.txt b/fastlane/metadata/android/en-US/changelogs/40104270.txt
new file mode 100644
index 0000000000..61db61727a
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/40104270.txt
@@ -0,0 +1,2 @@
+Main changes in this version: Various bug fixes and stability improvements.
+Full changelog: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/en-US/changelogs/40104280.txt b/fastlane/metadata/android/en-US/changelogs/40104280.txt
new file mode 100644
index 0000000000..61db61727a
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/40104280.txt
@@ -0,0 +1,2 @@
+Main changes in this version: Various bug fixes and stability improvements.
+Full changelog: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/en-US/changelogs/40104300.txt b/fastlane/metadata/android/en-US/changelogs/40104300.txt
new file mode 100644
index 0000000000..c0b3284c4f
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/40104300.txt
@@ -0,0 +1,2 @@
+Main changes in this version: Enables the improved sign in and sign up journeys.
+Full changelog: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/en-US/changelogs/40104310.txt b/fastlane/metadata/android/en-US/changelogs/40104310.txt
new file mode 100644
index 0000000000..c0b3284c4f
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/40104310.txt
@@ -0,0 +1,2 @@
+Main changes in this version: Enables the improved sign in and sign up journeys.
+Full changelog: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/en-US/changelogs/40104320.txt b/fastlane/metadata/android/en-US/changelogs/40104320.txt
new file mode 100644
index 0000000000..61db61727a
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/40104320.txt
@@ -0,0 +1,2 @@
+Main changes in this version: Various bug fixes and stability improvements.
+Full changelog: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/et/changelogs/40104160.txt b/fastlane/metadata/android/et/changelogs/40104160.txt
new file mode 100644
index 0000000000..aa5a341dd3
--- /dev/null
+++ b/fastlane/metadata/android/et/changelogs/40104160.txt
@@ -0,0 +1,2 @@
+Põhilised muutused selles versioonis: krüptitud sõnumite parem haldus, lisaks pisiparandused ja stabiilsust parandavad kohendused.
+Kogu ingliskeelne muudatuste logi: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/et/changelogs/40104180.txt b/fastlane/metadata/android/et/changelogs/40104180.txt
new file mode 100644
index 0000000000..1df5ac4176
--- /dev/null
+++ b/fastlane/metadata/android/et/changelogs/40104180.txt
@@ -0,0 +1,2 @@
+Põhilised muutused selles versioonis: erinevate vigade parandused ja stabiilsust edendavad kohendused.
+Kogu ingliskeelne muudatuste logi: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/et/changelogs/40104190.txt b/fastlane/metadata/android/et/changelogs/40104190.txt
new file mode 100644
index 0000000000..1df5ac4176
--- /dev/null
+++ b/fastlane/metadata/android/et/changelogs/40104190.txt
@@ -0,0 +1,2 @@
+Põhilised muutused selles versioonis: erinevate vigade parandused ja stabiilsust edendavad kohendused.
+Kogu ingliskeelne muudatuste logi: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/et/changelogs/40104200.txt b/fastlane/metadata/android/et/changelogs/40104200.txt
new file mode 100644
index 0000000000..1df5ac4176
--- /dev/null
+++ b/fastlane/metadata/android/et/changelogs/40104200.txt
@@ -0,0 +1,2 @@
+Põhilised muutused selles versioonis: erinevate vigade parandused ja stabiilsust edendavad kohendused.
+Kogu ingliskeelne muudatuste logi: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/et/changelogs/40104220.txt b/fastlane/metadata/android/et/changelogs/40104220.txt
new file mode 100644
index 0000000000..1df5ac4176
--- /dev/null
+++ b/fastlane/metadata/android/et/changelogs/40104220.txt
@@ -0,0 +1,2 @@
+Põhilised muutused selles versioonis: erinevate vigade parandused ja stabiilsust edendavad kohendused.
+Kogu ingliskeelne muudatuste logi: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/et/changelogs/40104230.txt b/fastlane/metadata/android/et/changelogs/40104230.txt
new file mode 100644
index 0000000000..1df5ac4176
--- /dev/null
+++ b/fastlane/metadata/android/et/changelogs/40104230.txt
@@ -0,0 +1,2 @@
+Põhilised muutused selles versioonis: erinevate vigade parandused ja stabiilsust edendavad kohendused.
+Kogu ingliskeelne muudatuste logi: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/et/changelogs/40104240.txt b/fastlane/metadata/android/et/changelogs/40104240.txt
new file mode 100644
index 0000000000..1df5ac4176
--- /dev/null
+++ b/fastlane/metadata/android/et/changelogs/40104240.txt
@@ -0,0 +1,2 @@
+Põhilised muutused selles versioonis: erinevate vigade parandused ja stabiilsust edendavad kohendused.
+Kogu ingliskeelne muudatuste logi: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/et/changelogs/40104250.txt b/fastlane/metadata/android/et/changelogs/40104250.txt
new file mode 100644
index 0000000000..1df5ac4176
--- /dev/null
+++ b/fastlane/metadata/android/et/changelogs/40104250.txt
@@ -0,0 +1,2 @@
+Põhilised muutused selles versioonis: erinevate vigade parandused ja stabiilsust edendavad kohendused.
+Kogu ingliskeelne muudatuste logi: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/et/changelogs/40104260.txt b/fastlane/metadata/android/et/changelogs/40104260.txt
new file mode 100644
index 0000000000..2241582817
--- /dev/null
+++ b/fastlane/metadata/android/et/changelogs/40104260.txt
@@ -0,0 +1,2 @@
+Põhilised muutused selles versioonis: võimalus kasutada tõukesõnumite jaoks FCM'i asemel UnifiedPush'i.
+Kogu ingliskeelne muudatuste logi: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/et/changelogs/40104270.txt b/fastlane/metadata/android/et/changelogs/40104270.txt
new file mode 100644
index 0000000000..1df5ac4176
--- /dev/null
+++ b/fastlane/metadata/android/et/changelogs/40104270.txt
@@ -0,0 +1,2 @@
+Põhilised muutused selles versioonis: erinevate vigade parandused ja stabiilsust edendavad kohendused.
+Kogu ingliskeelne muudatuste logi: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/et/changelogs/40104280.txt b/fastlane/metadata/android/et/changelogs/40104280.txt
new file mode 100644
index 0000000000..1df5ac4176
--- /dev/null
+++ b/fastlane/metadata/android/et/changelogs/40104280.txt
@@ -0,0 +1,2 @@
+Põhilised muutused selles versioonis: erinevate vigade parandused ja stabiilsust edendavad kohendused.
+Kogu ingliskeelne muudatuste logi: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/fa/changelogs/40104160.txt b/fastlane/metadata/android/fa/changelogs/40104160.txt
new file mode 100644
index 0000000000..1687ba2419
--- /dev/null
+++ b/fastlane/metadata/android/fa/changelogs/40104160.txt
@@ -0,0 +1,2 @@
+تغییرات عمده در این نگارش: مدیریت بهتر پیامهای رمزگذاشته. رفع اشکالهای مختلف و بهبودهای پایداری.
+گزارش دگرگونی کامل: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/fa/changelogs/40104180.txt b/fastlane/metadata/android/fa/changelogs/40104180.txt
new file mode 100644
index 0000000000..29efb95925
--- /dev/null
+++ b/fastlane/metadata/android/fa/changelogs/40104180.txt
@@ -0,0 +1,2 @@
+تغییرات عمده در این نگارش: رفع اشکالهای مختلف و بهبودهای پایداری.
+گزارش دگرگونی کامل: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/fa/changelogs/40104190.txt b/fastlane/metadata/android/fa/changelogs/40104190.txt
new file mode 100644
index 0000000000..29efb95925
--- /dev/null
+++ b/fastlane/metadata/android/fa/changelogs/40104190.txt
@@ -0,0 +1,2 @@
+تغییرات عمده در این نگارش: رفع اشکالهای مختلف و بهبودهای پایداری.
+گزارش دگرگونی کامل: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/fa/changelogs/40104200.txt b/fastlane/metadata/android/fa/changelogs/40104200.txt
new file mode 100644
index 0000000000..29efb95925
--- /dev/null
+++ b/fastlane/metadata/android/fa/changelogs/40104200.txt
@@ -0,0 +1,2 @@
+تغییرات عمده در این نگارش: رفع اشکالهای مختلف و بهبودهای پایداری.
+گزارش دگرگونی کامل: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/fa/changelogs/40104220.txt b/fastlane/metadata/android/fa/changelogs/40104220.txt
new file mode 100644
index 0000000000..29efb95925
--- /dev/null
+++ b/fastlane/metadata/android/fa/changelogs/40104220.txt
@@ -0,0 +1,2 @@
+تغییرات عمده در این نگارش: رفع اشکالهای مختلف و بهبودهای پایداری.
+گزارش دگرگونی کامل: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/fa/changelogs/40104230.txt b/fastlane/metadata/android/fa/changelogs/40104230.txt
new file mode 100644
index 0000000000..29efb95925
--- /dev/null
+++ b/fastlane/metadata/android/fa/changelogs/40104230.txt
@@ -0,0 +1,2 @@
+تغییرات عمده در این نگارش: رفع اشکالهای مختلف و بهبودهای پایداری.
+گزارش دگرگونی کامل: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/fa/changelogs/40104240.txt b/fastlane/metadata/android/fa/changelogs/40104240.txt
new file mode 100644
index 0000000000..29efb95925
--- /dev/null
+++ b/fastlane/metadata/android/fa/changelogs/40104240.txt
@@ -0,0 +1,2 @@
+تغییرات عمده در این نگارش: رفع اشکالهای مختلف و بهبودهای پایداری.
+گزارش دگرگونی کامل: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/fa/changelogs/40104250.txt b/fastlane/metadata/android/fa/changelogs/40104250.txt
new file mode 100644
index 0000000000..29efb95925
--- /dev/null
+++ b/fastlane/metadata/android/fa/changelogs/40104250.txt
@@ -0,0 +1,2 @@
+تغییرات عمده در این نگارش: رفع اشکالهای مختلف و بهبودهای پایداری.
+گزارش دگرگونی کامل: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/fa/changelogs/40104260.txt b/fastlane/metadata/android/fa/changelogs/40104260.txt
new file mode 100644
index 0000000000..2e6de40015
--- /dev/null
+++ b/fastlane/metadata/android/fa/changelogs/40104260.txt
@@ -0,0 +1,2 @@
+تغییرات عمده در این نگارش: استفاده از UnifiedPush و اجازه به کاربر برای داشتن آگاهیهای ارسالی بدون FCM.
+گزارش دگرگونی کامل: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/fa/changelogs/40104270.txt b/fastlane/metadata/android/fa/changelogs/40104270.txt
new file mode 100644
index 0000000000..29efb95925
--- /dev/null
+++ b/fastlane/metadata/android/fa/changelogs/40104270.txt
@@ -0,0 +1,2 @@
+تغییرات عمده در این نگارش: رفع اشکالهای مختلف و بهبودهای پایداری.
+گزارش دگرگونی کامل: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/fa/changelogs/40104280.txt b/fastlane/metadata/android/fa/changelogs/40104280.txt
new file mode 100644
index 0000000000..29efb95925
--- /dev/null
+++ b/fastlane/metadata/android/fa/changelogs/40104280.txt
@@ -0,0 +1,2 @@
+تغییرات عمده در این نگارش: رفع اشکالهای مختلف و بهبودهای پایداری.
+گزارش دگرگونی کامل: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/fr-FR/changelogs/40104160.txt b/fastlane/metadata/android/fr-FR/changelogs/40104160.txt
new file mode 100644
index 0000000000..6a19c6ea39
--- /dev/null
+++ b/fastlane/metadata/android/fr-FR/changelogs/40104160.txt
@@ -0,0 +1,2 @@
+Principaux changements pour cette version : Meilleure gestion des messages chiffrés. Plusieurs corrections de bogues et d’améliorations de stabilité.
+Intégralité des changements : https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/fr-FR/changelogs/40104180.txt b/fastlane/metadata/android/fr-FR/changelogs/40104180.txt
new file mode 100644
index 0000000000..fe61fd021c
--- /dev/null
+++ b/fastlane/metadata/android/fr-FR/changelogs/40104180.txt
@@ -0,0 +1,2 @@
+Principaux changements pour cette version : Plusieurs corrections de bogues et d’améliorations de stabilité.
+Intégralité des changements : https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/fr-FR/changelogs/40104190.txt b/fastlane/metadata/android/fr-FR/changelogs/40104190.txt
new file mode 100644
index 0000000000..fe61fd021c
--- /dev/null
+++ b/fastlane/metadata/android/fr-FR/changelogs/40104190.txt
@@ -0,0 +1,2 @@
+Principaux changements pour cette version : Plusieurs corrections de bogues et d’améliorations de stabilité.
+Intégralité des changements : https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/fr-FR/changelogs/40104200.txt b/fastlane/metadata/android/fr-FR/changelogs/40104200.txt
new file mode 100644
index 0000000000..fe61fd021c
--- /dev/null
+++ b/fastlane/metadata/android/fr-FR/changelogs/40104200.txt
@@ -0,0 +1,2 @@
+Principaux changements pour cette version : Plusieurs corrections de bogues et d’améliorations de stabilité.
+Intégralité des changements : https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/fr-FR/changelogs/40104220.txt b/fastlane/metadata/android/fr-FR/changelogs/40104220.txt
new file mode 100644
index 0000000000..fe61fd021c
--- /dev/null
+++ b/fastlane/metadata/android/fr-FR/changelogs/40104220.txt
@@ -0,0 +1,2 @@
+Principaux changements pour cette version : Plusieurs corrections de bogues et d’améliorations de stabilité.
+Intégralité des changements : https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/fr-FR/changelogs/40104230.txt b/fastlane/metadata/android/fr-FR/changelogs/40104230.txt
new file mode 100644
index 0000000000..fe61fd021c
--- /dev/null
+++ b/fastlane/metadata/android/fr-FR/changelogs/40104230.txt
@@ -0,0 +1,2 @@
+Principaux changements pour cette version : Plusieurs corrections de bogues et d’améliorations de stabilité.
+Intégralité des changements : https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/fr-FR/changelogs/40104240.txt b/fastlane/metadata/android/fr-FR/changelogs/40104240.txt
new file mode 100644
index 0000000000..fe61fd021c
--- /dev/null
+++ b/fastlane/metadata/android/fr-FR/changelogs/40104240.txt
@@ -0,0 +1,2 @@
+Principaux changements pour cette version : Plusieurs corrections de bogues et d’améliorations de stabilité.
+Intégralité des changements : https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/fr-FR/changelogs/40104250.txt b/fastlane/metadata/android/fr-FR/changelogs/40104250.txt
new file mode 100644
index 0000000000..fe61fd021c
--- /dev/null
+++ b/fastlane/metadata/android/fr-FR/changelogs/40104250.txt
@@ -0,0 +1,2 @@
+Principaux changements pour cette version : Plusieurs corrections de bogues et d’améliorations de stabilité.
+Intégralité des changements : https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/fr-FR/changelogs/40104260.txt b/fastlane/metadata/android/fr-FR/changelogs/40104260.txt
new file mode 100644
index 0000000000..2abff13ba4
--- /dev/null
+++ b/fastlane/metadata/android/fr-FR/changelogs/40104260.txt
@@ -0,0 +1,2 @@
+Principaux changements pour cette version : Utilisation de UnifiedPush qui permet aux utilisateur d’utiliser « push » sans FCM.
+Intégralité des changements : https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/fr-FR/changelogs/40104270.txt b/fastlane/metadata/android/fr-FR/changelogs/40104270.txt
new file mode 100644
index 0000000000..fe61fd021c
--- /dev/null
+++ b/fastlane/metadata/android/fr-FR/changelogs/40104270.txt
@@ -0,0 +1,2 @@
+Principaux changements pour cette version : Plusieurs corrections de bogues et d’améliorations de stabilité.
+Intégralité des changements : https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/fr-FR/changelogs/40104280.txt b/fastlane/metadata/android/fr-FR/changelogs/40104280.txt
new file mode 100644
index 0000000000..fe61fd021c
--- /dev/null
+++ b/fastlane/metadata/android/fr-FR/changelogs/40104280.txt
@@ -0,0 +1,2 @@
+Principaux changements pour cette version : Plusieurs corrections de bogues et d’améliorations de stabilité.
+Intégralité des changements : https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/gl/changelogs/40104160.txt b/fastlane/metadata/android/gl/changelogs/40104160.txt
new file mode 100644
index 0000000000..ee2cde15ad
--- /dev/null
+++ b/fastlane/metadata/android/gl/changelogs/40104160.txt
@@ -0,0 +1,2 @@
+Principais cambios nesta versión: melloras na xestión das mensaxes cifradas. Varios arranxos e melloras na estabilidade.
+Rexistro completo dos cambios: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/gl/changelogs/40104180.txt b/fastlane/metadata/android/gl/changelogs/40104180.txt
new file mode 100644
index 0000000000..532464f402
--- /dev/null
+++ b/fastlane/metadata/android/gl/changelogs/40104180.txt
@@ -0,0 +1,2 @@
+Principais cambios nesta versión: varios arranxos e melloras na estabilidade.
+Rexistro completo dos cambios: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/gl/changelogs/40104190.txt b/fastlane/metadata/android/gl/changelogs/40104190.txt
new file mode 100644
index 0000000000..532464f402
--- /dev/null
+++ b/fastlane/metadata/android/gl/changelogs/40104190.txt
@@ -0,0 +1,2 @@
+Principais cambios nesta versión: varios arranxos e melloras na estabilidade.
+Rexistro completo dos cambios: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/gl/changelogs/40104200.txt b/fastlane/metadata/android/gl/changelogs/40104200.txt
new file mode 100644
index 0000000000..532464f402
--- /dev/null
+++ b/fastlane/metadata/android/gl/changelogs/40104200.txt
@@ -0,0 +1,2 @@
+Principais cambios nesta versión: varios arranxos e melloras na estabilidade.
+Rexistro completo dos cambios: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/gl/changelogs/40104220.txt b/fastlane/metadata/android/gl/changelogs/40104220.txt
new file mode 100644
index 0000000000..532464f402
--- /dev/null
+++ b/fastlane/metadata/android/gl/changelogs/40104220.txt
@@ -0,0 +1,2 @@
+Principais cambios nesta versión: varios arranxos e melloras na estabilidade.
+Rexistro completo dos cambios: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/gl/changelogs/40104230.txt b/fastlane/metadata/android/gl/changelogs/40104230.txt
new file mode 100644
index 0000000000..532464f402
--- /dev/null
+++ b/fastlane/metadata/android/gl/changelogs/40104230.txt
@@ -0,0 +1,2 @@
+Principais cambios nesta versión: varios arranxos e melloras na estabilidade.
+Rexistro completo dos cambios: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/gl/changelogs/40104240.txt b/fastlane/metadata/android/gl/changelogs/40104240.txt
new file mode 100644
index 0000000000..532464f402
--- /dev/null
+++ b/fastlane/metadata/android/gl/changelogs/40104240.txt
@@ -0,0 +1,2 @@
+Principais cambios nesta versión: varios arranxos e melloras na estabilidade.
+Rexistro completo dos cambios: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/gl/changelogs/40104250.txt b/fastlane/metadata/android/gl/changelogs/40104250.txt
new file mode 100644
index 0000000000..532464f402
--- /dev/null
+++ b/fastlane/metadata/android/gl/changelogs/40104250.txt
@@ -0,0 +1,2 @@
+Principais cambios nesta versión: varios arranxos e melloras na estabilidade.
+Rexistro completo dos cambios: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/gl/changelogs/40104260.txt b/fastlane/metadata/android/gl/changelogs/40104260.txt
new file mode 100644
index 0000000000..a863d73cc4
--- /dev/null
+++ b/fastlane/metadata/android/gl/changelogs/40104260.txt
@@ -0,0 +1,2 @@
+Principais cambios nesta versión: Utiliza UnifiedPush e permite á usuaria obter notificacións sen FCM.
+Rexistro completo dos cambios: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/gl/changelogs/40104270.txt b/fastlane/metadata/android/gl/changelogs/40104270.txt
new file mode 100644
index 0000000000..532464f402
--- /dev/null
+++ b/fastlane/metadata/android/gl/changelogs/40104270.txt
@@ -0,0 +1,2 @@
+Principais cambios nesta versión: varios arranxos e melloras na estabilidade.
+Rexistro completo dos cambios: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/gl/full_description.txt b/fastlane/metadata/android/gl/full_description.txt
new file mode 100644
index 0000000000..3502e3ba58
--- /dev/null
+++ b/fastlane/metadata/android/gl/full_description.txt
@@ -0,0 +1,42 @@
+Element é tanto unha mensaxería segura e unha app de productividade para o traballo en equipo, perfecta para conversas de grupos con traballo remoto. Esta app de chat usa cifrado de extremo-a-extremo para proporcionar video conferencias seguras, compartición de ficheiros e chamadas de voz.
+
+Características de Element incluídas:
+- Ferramentas avanzadas para a comunicación en liña
+- Mensaxes completamente cifradas para permitir a comunicación corporativa, incluso para traballo remoto
+- Chat descentralizado baseado no sistema de código aberto Matrix
+- Compartición segura de ficheiros con datos cifrados na xestión de proxectos
+- Chats de vídeo con Voz sobre IP en compartición de pantalla
+- Integración doada con outras ferramentas de colaboración en liña, ferramentas de xestión de proxectos, servizos VoIP e outras apps de mensaxería para equipos
+
+Element é completamente diferente a outras apps de mensaxería e traballo en equipo. Funciona grazas a Matrix, unha rede aberta para mensaxería segura e descentralizada. Permite a hospedaxe na infraestructura propia para proporcionar o maior grao de propiedade e control sobre os teus datos e mensaxes.
+
+Mensaxería privada e cifrada
+Element protéxete da publicidade non solicitada, minería de datos e burbullas de contido. Tamén protexe os teus datos, chamadas de vídeo e voz cifradas de extremo-a-extremo así como verificación con sinatura dos dispositivos.
+
+Element pon baixo o teu control a túa privacidade permitíndoche comunicarte de xeito seguro con calquera a través da rede Matrix, ou en outras ferramentas de colaboración para empresas ao estar integrada en apps como Slack.
+
+Element na túa infraestructura
+Para un maior control sobre os teus datos sensibles e comunicacións, podes hospedar Element ou elexir calquera hóspede baseado en Matrix - un estándar para comunicación descentralizado e de código aberto. Element proporciona privacidade e seguridade así como flexibilidade para a integración.
+
+Os teus datos
+Ti decides onde gardas os teus datos e mensaxes. Sen o risco da minería de datos ou acceso por terceiras partes.
+
+Element ponte ao mando de varios xeitos:
+1. Consigue unha conta gratuíta no servidor público matrix.org hospedado polos desenvolvedores de Matrix, ou elixe entre miles de servidores públicos xestionados por voluntarias
+2. Hospeda a túa conta na túa propia infraestructura IT
+3. Crea unha conta nun servidor personalizado simplemente subscribíndote á plataforma de hospedaxe Element Matrix Services
+
+Mensaxería e Colaboración abertas
+Podes conversar con calquera na rede Matrix, tanto se usan Element ou outra app Matrix ou incluso unha mensaxería diferente.
+
+Super segura
+Cifrado real de extremo-a-extremo (só quen participa na conversa pode descifrar as mensaxes), e verificación con sinatura cruzada dos dispositivos.
+
+Comunicación e integración completas
+Mensaxería, chamadas de voz e vídeo, compartición de ficheiros, compartición de pantalla e moitas máis integracións, bots e widgets. Crea salas, comunidades, mantén o contacto e saca adiante o traballo.
+
+Continúa onde o deixaches
+Sigue en contacto alá onde estés grazas ao historial sincronizado de mensaxería entre tódolos dispositivos e na web https://app.element.io
+
+Código aberto
+Element Android é un proxecto de código aberto, hospedado en GitHub. Informa de fallos e/ou contribúe ao seu desenvolvemento en https://github.com/vector-im/element-android
diff --git a/fastlane/metadata/android/gl/short_description.txt b/fastlane/metadata/android/gl/short_description.txt
new file mode 100644
index 0000000000..7c7f65bf61
--- /dev/null
+++ b/fastlane/metadata/android/gl/short_description.txt
@@ -0,0 +1 @@
+Mensaxería en grupo - mensaxería cifrada, chat en grupo e videochamadas
diff --git a/fastlane/metadata/android/gl/title.txt b/fastlane/metadata/android/gl/title.txt
new file mode 100644
index 0000000000..0fb73bc324
--- /dev/null
+++ b/fastlane/metadata/android/gl/title.txt
@@ -0,0 +1 @@
+Element - Mensaxería Segura
diff --git a/fastlane/metadata/android/hu-HU/title.txt b/fastlane/metadata/android/hu-HU/title.txt
index c463dea393..907f907f99 100644
--- a/fastlane/metadata/android/hu-HU/title.txt
+++ b/fastlane/metadata/android/hu-HU/title.txt
@@ -1 +1 @@
-Element - Biztonságos üzenetküldő
+Element
diff --git a/fastlane/metadata/android/id/changelogs/40104160.txt b/fastlane/metadata/android/id/changelogs/40104160.txt
new file mode 100644
index 0000000000..8f248ffed4
--- /dev/null
+++ b/fastlane/metadata/android/id/changelogs/40104160.txt
@@ -0,0 +1,2 @@
+Perubahan utama dalam versi ini: Pengelolaan pesan terenkripsi lebih baik. Banyak perbaikan kutu dan perbaikan stabilitas.
+Catatan perubahan lanjutan: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/id/changelogs/40104180.txt b/fastlane/metadata/android/id/changelogs/40104180.txt
new file mode 100644
index 0000000000..1017951d47
--- /dev/null
+++ b/fastlane/metadata/android/id/changelogs/40104180.txt
@@ -0,0 +1,2 @@
+Perubahan utama dalam versi ini: Banyak perbaikan kutu dan perbaikan stabilitas.
+Catatan perubahan lanjutan: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/id/changelogs/40104190.txt b/fastlane/metadata/android/id/changelogs/40104190.txt
new file mode 100644
index 0000000000..1017951d47
--- /dev/null
+++ b/fastlane/metadata/android/id/changelogs/40104190.txt
@@ -0,0 +1,2 @@
+Perubahan utama dalam versi ini: Banyak perbaikan kutu dan perbaikan stabilitas.
+Catatan perubahan lanjutan: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/id/changelogs/40104200.txt b/fastlane/metadata/android/id/changelogs/40104200.txt
new file mode 100644
index 0000000000..1017951d47
--- /dev/null
+++ b/fastlane/metadata/android/id/changelogs/40104200.txt
@@ -0,0 +1,2 @@
+Perubahan utama dalam versi ini: Banyak perbaikan kutu dan perbaikan stabilitas.
+Catatan perubahan lanjutan: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/id/changelogs/40104220.txt b/fastlane/metadata/android/id/changelogs/40104220.txt
new file mode 100644
index 0000000000..1017951d47
--- /dev/null
+++ b/fastlane/metadata/android/id/changelogs/40104220.txt
@@ -0,0 +1,2 @@
+Perubahan utama dalam versi ini: Banyak perbaikan kutu dan perbaikan stabilitas.
+Catatan perubahan lanjutan: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/id/changelogs/40104230.txt b/fastlane/metadata/android/id/changelogs/40104230.txt
new file mode 100644
index 0000000000..1017951d47
--- /dev/null
+++ b/fastlane/metadata/android/id/changelogs/40104230.txt
@@ -0,0 +1,2 @@
+Perubahan utama dalam versi ini: Banyak perbaikan kutu dan perbaikan stabilitas.
+Catatan perubahan lanjutan: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/id/changelogs/40104240.txt b/fastlane/metadata/android/id/changelogs/40104240.txt
new file mode 100644
index 0000000000..1017951d47
--- /dev/null
+++ b/fastlane/metadata/android/id/changelogs/40104240.txt
@@ -0,0 +1,2 @@
+Perubahan utama dalam versi ini: Banyak perbaikan kutu dan perbaikan stabilitas.
+Catatan perubahan lanjutan: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/id/changelogs/40104250.txt b/fastlane/metadata/android/id/changelogs/40104250.txt
new file mode 100644
index 0000000000..1017951d47
--- /dev/null
+++ b/fastlane/metadata/android/id/changelogs/40104250.txt
@@ -0,0 +1,2 @@
+Perubahan utama dalam versi ini: Banyak perbaikan kutu dan perbaikan stabilitas.
+Catatan perubahan lanjutan: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/id/changelogs/40104260.txt b/fastlane/metadata/android/id/changelogs/40104260.txt
new file mode 100644
index 0000000000..bfd9637fda
--- /dev/null
+++ b/fastlane/metadata/android/id/changelogs/40104260.txt
@@ -0,0 +1,2 @@
+Perubahan utama dalam versi ini: Dukungan UnifiedPush, memungkinkan pengguna untuk diberitahukan tanpa FCM.
+Catatan perubahan lanjutan: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/id/changelogs/40104270.txt b/fastlane/metadata/android/id/changelogs/40104270.txt
new file mode 100644
index 0000000000..1017951d47
--- /dev/null
+++ b/fastlane/metadata/android/id/changelogs/40104270.txt
@@ -0,0 +1,2 @@
+Perubahan utama dalam versi ini: Banyak perbaikan kutu dan perbaikan stabilitas.
+Catatan perubahan lanjutan: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/id/changelogs/40104280.txt b/fastlane/metadata/android/id/changelogs/40104280.txt
new file mode 100644
index 0000000000..1017951d47
--- /dev/null
+++ b/fastlane/metadata/android/id/changelogs/40104280.txt
@@ -0,0 +1,2 @@
+Perubahan utama dalam versi ini: Banyak perbaikan kutu dan perbaikan stabilitas.
+Catatan perubahan lanjutan: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/it-IT/changelogs/40104160.txt b/fastlane/metadata/android/it-IT/changelogs/40104160.txt
new file mode 100644
index 0000000000..943a42de99
--- /dev/null
+++ b/fastlane/metadata/android/it-IT/changelogs/40104160.txt
@@ -0,0 +1,2 @@
+Modifiche principali in questa versione: migliorata la gestione dei messaggi cifrati. Varie correzioni e miglioramenti della stabilità.
+Cronologia completa: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/it-IT/changelogs/40104180.txt b/fastlane/metadata/android/it-IT/changelogs/40104180.txt
new file mode 100644
index 0000000000..556a6fc7ea
--- /dev/null
+++ b/fastlane/metadata/android/it-IT/changelogs/40104180.txt
@@ -0,0 +1,2 @@
+Modifiche principali in questa versione: varie correzioni di errori e miglioramenti della stabilità.
+Cronologia completa: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/it-IT/changelogs/40104190.txt b/fastlane/metadata/android/it-IT/changelogs/40104190.txt
new file mode 100644
index 0000000000..556a6fc7ea
--- /dev/null
+++ b/fastlane/metadata/android/it-IT/changelogs/40104190.txt
@@ -0,0 +1,2 @@
+Modifiche principali in questa versione: varie correzioni di errori e miglioramenti della stabilità.
+Cronologia completa: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/it-IT/changelogs/40104200.txt b/fastlane/metadata/android/it-IT/changelogs/40104200.txt
new file mode 100644
index 0000000000..556a6fc7ea
--- /dev/null
+++ b/fastlane/metadata/android/it-IT/changelogs/40104200.txt
@@ -0,0 +1,2 @@
+Modifiche principali in questa versione: varie correzioni di errori e miglioramenti della stabilità.
+Cronologia completa: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/it-IT/changelogs/40104220.txt b/fastlane/metadata/android/it-IT/changelogs/40104220.txt
new file mode 100644
index 0000000000..556a6fc7ea
--- /dev/null
+++ b/fastlane/metadata/android/it-IT/changelogs/40104220.txt
@@ -0,0 +1,2 @@
+Modifiche principali in questa versione: varie correzioni di errori e miglioramenti della stabilità.
+Cronologia completa: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/it-IT/changelogs/40104230.txt b/fastlane/metadata/android/it-IT/changelogs/40104230.txt
new file mode 100644
index 0000000000..556a6fc7ea
--- /dev/null
+++ b/fastlane/metadata/android/it-IT/changelogs/40104230.txt
@@ -0,0 +1,2 @@
+Modifiche principali in questa versione: varie correzioni di errori e miglioramenti della stabilità.
+Cronologia completa: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/it-IT/changelogs/40104240.txt b/fastlane/metadata/android/it-IT/changelogs/40104240.txt
new file mode 100644
index 0000000000..556a6fc7ea
--- /dev/null
+++ b/fastlane/metadata/android/it-IT/changelogs/40104240.txt
@@ -0,0 +1,2 @@
+Modifiche principali in questa versione: varie correzioni di errori e miglioramenti della stabilità.
+Cronologia completa: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/it-IT/changelogs/40104250.txt b/fastlane/metadata/android/it-IT/changelogs/40104250.txt
new file mode 100644
index 0000000000..556a6fc7ea
--- /dev/null
+++ b/fastlane/metadata/android/it-IT/changelogs/40104250.txt
@@ -0,0 +1,2 @@
+Modifiche principali in questa versione: varie correzioni di errori e miglioramenti della stabilità.
+Cronologia completa: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/it-IT/changelogs/40104260.txt b/fastlane/metadata/android/it-IT/changelogs/40104260.txt
new file mode 100644
index 0000000000..d52ed6b769
--- /dev/null
+++ b/fastlane/metadata/android/it-IT/changelogs/40104260.txt
@@ -0,0 +1,2 @@
+Modifiche principali in questa versione: utilizza UnifiedPush e consente all'utente di avere notifiche push senza FCM.
+Cronologia completa: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/it-IT/changelogs/40104270.txt b/fastlane/metadata/android/it-IT/changelogs/40104270.txt
new file mode 100644
index 0000000000..556a6fc7ea
--- /dev/null
+++ b/fastlane/metadata/android/it-IT/changelogs/40104270.txt
@@ -0,0 +1,2 @@
+Modifiche principali in questa versione: varie correzioni di errori e miglioramenti della stabilità.
+Cronologia completa: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/it-IT/changelogs/40104280.txt b/fastlane/metadata/android/it-IT/changelogs/40104280.txt
new file mode 100644
index 0000000000..556a6fc7ea
--- /dev/null
+++ b/fastlane/metadata/android/it-IT/changelogs/40104280.txt
@@ -0,0 +1,2 @@
+Modifiche principali in questa versione: varie correzioni di errori e miglioramenti della stabilità.
+Cronologia completa: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/iw-IL/title.txt b/fastlane/metadata/android/iw-IL/title.txt
index d8849a5023..56ae517696 100644
--- a/fastlane/metadata/android/iw-IL/title.txt
+++ b/fastlane/metadata/android/iw-IL/title.txt
@@ -1 +1 @@
-אלמנט (בעבר Riot.im)
+אלמנט - התכתבות מאובטחת
diff --git a/fastlane/metadata/android/pl-PL/changelogs/40100170.txt b/fastlane/metadata/android/pl-PL/changelogs/40100170.txt
new file mode 100644
index 0000000000..1105b2c190
--- /dev/null
+++ b/fastlane/metadata/android/pl-PL/changelogs/40100170.txt
@@ -0,0 +1,2 @@
+Główne zmiany w tej wersji: Poprawki błędów!
+Pełna lista zmian: https://github.com/vector-im/element-android/releases/tag/v1.0.17
diff --git a/fastlane/metadata/android/pl-PL/changelogs/40101000.txt b/fastlane/metadata/android/pl-PL/changelogs/40101000.txt
new file mode 100644
index 0000000000..7dac243a08
--- /dev/null
+++ b/fastlane/metadata/android/pl-PL/changelogs/40101000.txt
@@ -0,0 +1,2 @@
+Główne zmiany w tej wersji: zwiększenie wydajności i poprawki błędów!
+Pełna lista zmian: https://github.com/vector-im/element-android/releases/tag/v1.1.0
diff --git a/fastlane/metadata/android/pl-PL/changelogs/40101010.txt b/fastlane/metadata/android/pl-PL/changelogs/40101010.txt
new file mode 100644
index 0000000000..54e9c04a20
--- /dev/null
+++ b/fastlane/metadata/android/pl-PL/changelogs/40101010.txt
@@ -0,0 +1,2 @@
+Główne zmiany w tej wersji: zwiększenie wydajności i poprawki błędów!
+Pełna lista zmian: https://github.com/vector-im/element-android/releases/tag/v1.1.1
diff --git a/fastlane/metadata/android/pl-PL/changelogs/40101020.txt b/fastlane/metadata/android/pl-PL/changelogs/40101020.txt
new file mode 100644
index 0000000000..b17faea32a
--- /dev/null
+++ b/fastlane/metadata/android/pl-PL/changelogs/40101020.txt
@@ -0,0 +1,2 @@
+Główne zmiany w tej wersji: zwiększenie wydajności i poprawki błędów!
+Pełna lista zmian: https://github.com/vector-im/element-android/releases/tag/v1.1.2
diff --git a/fastlane/metadata/android/pl-PL/changelogs/40101030.txt b/fastlane/metadata/android/pl-PL/changelogs/40101030.txt
new file mode 100644
index 0000000000..12fc681102
--- /dev/null
+++ b/fastlane/metadata/android/pl-PL/changelogs/40101030.txt
@@ -0,0 +1,2 @@
+Główne zmiany w tej wersji: zwiększenie wydajności i poprawki błędów!
+Pełna lista zmian: https://github.com/vector-im/element-android/releases/tag/v1.1.3
diff --git a/fastlane/metadata/android/pl-PL/changelogs/40101040.txt b/fastlane/metadata/android/pl-PL/changelogs/40101040.txt
new file mode 100644
index 0000000000..19edf73b7b
--- /dev/null
+++ b/fastlane/metadata/android/pl-PL/changelogs/40101040.txt
@@ -0,0 +1,2 @@
+Główne zmiany w tej wersji: zwiększenie wydajności i poprawki błędów!
+Pełna lista zmian: https://github.com/vector-im/element-android/releases/tag/v1.1.4
diff --git a/fastlane/metadata/android/pl-PL/changelogs/40101050.txt b/fastlane/metadata/android/pl-PL/changelogs/40101050.txt
new file mode 100644
index 0000000000..a51a43ab70
--- /dev/null
+++ b/fastlane/metadata/android/pl-PL/changelogs/40101050.txt
@@ -0,0 +1,2 @@
+Główne zmiany w tej wersji: poprawki dla wersji 1.1.4.
+Pełna lista zmian: https://github.com/vector-im/element-android/releases/tag/v1.1.5
diff --git a/fastlane/metadata/android/pl-PL/changelogs/40101060.txt b/fastlane/metadata/android/pl-PL/changelogs/40101060.txt
new file mode 100644
index 0000000000..17af495632
--- /dev/null
+++ b/fastlane/metadata/android/pl-PL/changelogs/40101060.txt
@@ -0,0 +1,2 @@
+Główne zmiany w tej wesji: poprawki dla wesji 1.1.5
+Pełna lista zmian: https://github.com/vector-im/element-android/releases/tag/v1.1.6
diff --git a/fastlane/metadata/android/pl-PL/changelogs/40101070.txt b/fastlane/metadata/android/pl-PL/changelogs/40101070.txt
new file mode 100644
index 0000000000..2959ba88e0
--- /dev/null
+++ b/fastlane/metadata/android/pl-PL/changelogs/40101070.txt
@@ -0,0 +1,2 @@
+Główne zmiany w tej wersji: Eksperymentalne wsparcie dla przestrzeni, Kompresowanie video przed wysłaniem.
+Pełna lista zmian: https://github.com/vector-im/element-android/releases/tag/v1.1.7
diff --git a/fastlane/metadata/android/pl-PL/changelogs/40101080.txt b/fastlane/metadata/android/pl-PL/changelogs/40101080.txt
new file mode 100644
index 0000000000..95f77a0f25
--- /dev/null
+++ b/fastlane/metadata/android/pl-PL/changelogs/40101080.txt
@@ -0,0 +1,2 @@
+Główne zmiany w tej wersji: Poprawki w przestrzeniach
+Pełna lista zmian https://github.com/vector-im/element-android/releases/tag/v1.1.8
diff --git a/fastlane/metadata/android/pl-PL/changelogs/40101090.txt b/fastlane/metadata/android/pl-PL/changelogs/40101090.txt
new file mode 100644
index 0000000000..0bc111fa70
--- /dev/null
+++ b/fastlane/metadata/android/pl-PL/changelogs/40101090.txt
@@ -0,0 +1,2 @@
+Główne zmiany w tej wersji: Dodano wsparcie dla sieci gitter.im .
+Pełna lista zmian: https://github.com/vector-im/element-android/releases/tag/v1.1.9
diff --git a/fastlane/metadata/android/pl-PL/changelogs/40101100.txt b/fastlane/metadata/android/pl-PL/changelogs/40101100.txt
new file mode 100644
index 0000000000..2eace7771d
--- /dev/null
+++ b/fastlane/metadata/android/pl-PL/changelogs/40101100.txt
@@ -0,0 +1,2 @@
+Główne zmiany w tej wersji: Nowe funkcje dla przestrzeni i aktualizacja motywu i stylu.
+Pełna lista zmian: https://github.com/vector-im/element-android/releases/tag/v1.1.10
diff --git a/fastlane/metadata/android/pl-PL/changelogs/40101110.txt b/fastlane/metadata/android/pl-PL/changelogs/40101110.txt
new file mode 100644
index 0000000000..5afc3ca5a7
--- /dev/null
+++ b/fastlane/metadata/android/pl-PL/changelogs/40101110.txt
@@ -0,0 +1,2 @@
+Główne zmiany w tej wersji: Dodano nowe funkcje do przestrzeni i zaktualizowano motyw i styl aplikacji. (poprawki błędóœ dla wesji 1.1.10)
+Pełna lista zmian: https://github.com/vector-im/element-android/releases/tag/v1.1.11
diff --git a/fastlane/metadata/android/pl-PL/changelogs/40104160.txt b/fastlane/metadata/android/pl-PL/changelogs/40104160.txt
new file mode 100644
index 0000000000..104ed45352
--- /dev/null
+++ b/fastlane/metadata/android/pl-PL/changelogs/40104160.txt
@@ -0,0 +1,2 @@
+Główne zmiany w tej wersji: Lepsze zarządzanie zaszyfrowanymi wiadomościami. , Poprawki błędów i stabilności.
+Pełna lista zmian: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/pl-PL/changelogs/40104180.txt b/fastlane/metadata/android/pl-PL/changelogs/40104180.txt
new file mode 100644
index 0000000000..5077ae400b
--- /dev/null
+++ b/fastlane/metadata/android/pl-PL/changelogs/40104180.txt
@@ -0,0 +1,2 @@
+Główne zmiany w tej wersji: Poprawki rozmaitych błędów i usprawnienia stabilności.
+Pełna lista zmian: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/pl-PL/changelogs/40104190.txt b/fastlane/metadata/android/pl-PL/changelogs/40104190.txt
new file mode 100644
index 0000000000..5077ae400b
--- /dev/null
+++ b/fastlane/metadata/android/pl-PL/changelogs/40104190.txt
@@ -0,0 +1,2 @@
+Główne zmiany w tej wersji: Poprawki rozmaitych błędów i usprawnienia stabilności.
+Pełna lista zmian: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/pl-PL/changelogs/40104200.txt b/fastlane/metadata/android/pl-PL/changelogs/40104200.txt
new file mode 100644
index 0000000000..5077ae400b
--- /dev/null
+++ b/fastlane/metadata/android/pl-PL/changelogs/40104200.txt
@@ -0,0 +1,2 @@
+Główne zmiany w tej wersji: Poprawki rozmaitych błędów i usprawnienia stabilności.
+Pełna lista zmian: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/pl-PL/changelogs/40104220.txt b/fastlane/metadata/android/pl-PL/changelogs/40104220.txt
new file mode 100644
index 0000000000..5077ae400b
--- /dev/null
+++ b/fastlane/metadata/android/pl-PL/changelogs/40104220.txt
@@ -0,0 +1,2 @@
+Główne zmiany w tej wersji: Poprawki rozmaitych błędów i usprawnienia stabilności.
+Pełna lista zmian: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/pl-PL/changelogs/40104230.txt b/fastlane/metadata/android/pl-PL/changelogs/40104230.txt
new file mode 100644
index 0000000000..5077ae400b
--- /dev/null
+++ b/fastlane/metadata/android/pl-PL/changelogs/40104230.txt
@@ -0,0 +1,2 @@
+Główne zmiany w tej wersji: Poprawki rozmaitych błędów i usprawnienia stabilności.
+Pełna lista zmian: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/pl-PL/changelogs/40104240.txt b/fastlane/metadata/android/pl-PL/changelogs/40104240.txt
new file mode 100644
index 0000000000..5077ae400b
--- /dev/null
+++ b/fastlane/metadata/android/pl-PL/changelogs/40104240.txt
@@ -0,0 +1,2 @@
+Główne zmiany w tej wersji: Poprawki rozmaitych błędów i usprawnienia stabilności.
+Pełna lista zmian: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/pl-PL/changelogs/40104250.txt b/fastlane/metadata/android/pl-PL/changelogs/40104250.txt
new file mode 100644
index 0000000000..5077ae400b
--- /dev/null
+++ b/fastlane/metadata/android/pl-PL/changelogs/40104250.txt
@@ -0,0 +1,2 @@
+Główne zmiany w tej wersji: Poprawki rozmaitych błędów i usprawnienia stabilności.
+Pełna lista zmian: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/pl-PL/changelogs/40104260.txt b/fastlane/metadata/android/pl-PL/changelogs/40104260.txt
new file mode 100644
index 0000000000..f24649b992
--- /dev/null
+++ b/fastlane/metadata/android/pl-PL/changelogs/40104260.txt
@@ -0,0 +1,2 @@
+Główne zmiany w tej wersji: Dodanie UnifiedPush aby umożliwić działanie powiadomień push bez FCM.
+Pełna lista zmian: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/pl-PL/changelogs/40104270.txt b/fastlane/metadata/android/pl-PL/changelogs/40104270.txt
new file mode 100644
index 0000000000..5077ae400b
--- /dev/null
+++ b/fastlane/metadata/android/pl-PL/changelogs/40104270.txt
@@ -0,0 +1,2 @@
+Główne zmiany w tej wersji: Poprawki rozmaitych błędów i usprawnienia stabilności.
+Pełna lista zmian: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/pl-PL/changelogs/40104280.txt b/fastlane/metadata/android/pl-PL/changelogs/40104280.txt
new file mode 100644
index 0000000000..5077ae400b
--- /dev/null
+++ b/fastlane/metadata/android/pl-PL/changelogs/40104280.txt
@@ -0,0 +1,2 @@
+Główne zmiany w tej wersji: Poprawki rozmaitych błędów i usprawnienia stabilności.
+Pełna lista zmian: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/pt-BR/changelogs/40104160.txt b/fastlane/metadata/android/pt-BR/changelogs/40104160.txt
new file mode 100644
index 0000000000..eec5dca30f
--- /dev/null
+++ b/fastlane/metadata/android/pt-BR/changelogs/40104160.txt
@@ -0,0 +1,2 @@
+Principais mudanças nesta versão: Melhor gerenciamento de mensagens encriptadas. Vários consertos de bugs e melhorias de estabilidade.
+Changelog completo: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/pt-BR/changelogs/40104180.txt b/fastlane/metadata/android/pt-BR/changelogs/40104180.txt
new file mode 100644
index 0000000000..6e11e92579
--- /dev/null
+++ b/fastlane/metadata/android/pt-BR/changelogs/40104180.txt
@@ -0,0 +1,2 @@
+Principais mudanças nesta versão: Vários consertos de bugs e melhorias de estabilidade.
+Changelog completo: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/pt-BR/changelogs/40104190.txt b/fastlane/metadata/android/pt-BR/changelogs/40104190.txt
new file mode 100644
index 0000000000..6e11e92579
--- /dev/null
+++ b/fastlane/metadata/android/pt-BR/changelogs/40104190.txt
@@ -0,0 +1,2 @@
+Principais mudanças nesta versão: Vários consertos de bugs e melhorias de estabilidade.
+Changelog completo: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/pt-BR/changelogs/40104200.txt b/fastlane/metadata/android/pt-BR/changelogs/40104200.txt
new file mode 100644
index 0000000000..6e11e92579
--- /dev/null
+++ b/fastlane/metadata/android/pt-BR/changelogs/40104200.txt
@@ -0,0 +1,2 @@
+Principais mudanças nesta versão: Vários consertos de bugs e melhorias de estabilidade.
+Changelog completo: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/pt-BR/changelogs/40104220.txt b/fastlane/metadata/android/pt-BR/changelogs/40104220.txt
new file mode 100644
index 0000000000..6e11e92579
--- /dev/null
+++ b/fastlane/metadata/android/pt-BR/changelogs/40104220.txt
@@ -0,0 +1,2 @@
+Principais mudanças nesta versão: Vários consertos de bugs e melhorias de estabilidade.
+Changelog completo: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/pt-BR/changelogs/40104230.txt b/fastlane/metadata/android/pt-BR/changelogs/40104230.txt
new file mode 100644
index 0000000000..6e11e92579
--- /dev/null
+++ b/fastlane/metadata/android/pt-BR/changelogs/40104230.txt
@@ -0,0 +1,2 @@
+Principais mudanças nesta versão: Vários consertos de bugs e melhorias de estabilidade.
+Changelog completo: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/pt-BR/changelogs/40104240.txt b/fastlane/metadata/android/pt-BR/changelogs/40104240.txt
new file mode 100644
index 0000000000..6e11e92579
--- /dev/null
+++ b/fastlane/metadata/android/pt-BR/changelogs/40104240.txt
@@ -0,0 +1,2 @@
+Principais mudanças nesta versão: Vários consertos de bugs e melhorias de estabilidade.
+Changelog completo: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/pt-BR/changelogs/40104250.txt b/fastlane/metadata/android/pt-BR/changelogs/40104250.txt
new file mode 100644
index 0000000000..6e11e92579
--- /dev/null
+++ b/fastlane/metadata/android/pt-BR/changelogs/40104250.txt
@@ -0,0 +1,2 @@
+Principais mudanças nesta versão: Vários consertos de bugs e melhorias de estabilidade.
+Changelog completo: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/pt-BR/changelogs/40104260.txt b/fastlane/metadata/android/pt-BR/changelogs/40104260.txt
new file mode 100644
index 0000000000..25d02aee8b
--- /dev/null
+++ b/fastlane/metadata/android/pt-BR/changelogs/40104260.txt
@@ -0,0 +1,2 @@
+Principais mudanças nesta versão: Usar UnifiedPush e permite usuária(o) ter push sem FCM.
+Changelog completo: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/pt-BR/changelogs/40104270.txt b/fastlane/metadata/android/pt-BR/changelogs/40104270.txt
new file mode 100644
index 0000000000..6e11e92579
--- /dev/null
+++ b/fastlane/metadata/android/pt-BR/changelogs/40104270.txt
@@ -0,0 +1,2 @@
+Principais mudanças nesta versão: Vários consertos de bugs e melhorias de estabilidade.
+Changelog completo: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/pt-BR/changelogs/40104280.txt b/fastlane/metadata/android/pt-BR/changelogs/40104280.txt
new file mode 100644
index 0000000000..6e11e92579
--- /dev/null
+++ b/fastlane/metadata/android/pt-BR/changelogs/40104280.txt
@@ -0,0 +1,2 @@
+Principais mudanças nesta versão: Vários consertos de bugs e melhorias de estabilidade.
+Changelog completo: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/ru-RU/changelogs/40104040.txt b/fastlane/metadata/android/ru-RU/changelogs/40104040.txt
new file mode 100644
index 0000000000..00904bc548
--- /dev/null
+++ b/fastlane/metadata/android/ru-RU/changelogs/40104040.txt
@@ -0,0 +1,2 @@
+Основные изменения в этой версии: обновлён индикатор набора сообщения. Исправлены известные ошибки и улучшена стабильность.
+Полный список изменений: https://github.com/vector-im/element-android/releases/tag/v1.4.4
diff --git a/fastlane/metadata/android/ru-RU/changelogs/40104060.txt b/fastlane/metadata/android/ru-RU/changelogs/40104060.txt
new file mode 100644
index 0000000000..e241853529
--- /dev/null
+++ b/fastlane/metadata/android/ru-RU/changelogs/40104060.txt
@@ -0,0 +1,2 @@
+Основные изменения в этой версии: Лента веток работает в реальном времени и быстрее. Различные исправления ошибок и улучшения стабильности.
+Полный список изменений: https://github.com/vector-im/element-android/releases/tag/v1.4.6
diff --git a/fastlane/metadata/android/ru-RU/changelogs/40104070.txt b/fastlane/metadata/android/ru-RU/changelogs/40104070.txt
new file mode 100644
index 0000000000..d53e18c58d
--- /dev/null
+++ b/fastlane/metadata/android/ru-RU/changelogs/40104070.txt
@@ -0,0 +1,2 @@
+Основные изменения в этой версии: Различные исправления ошибок и улучшения стабильности.
+Полный список изменений: https://github.com/vector-im/element-android/releases/tag/v1.4.7
diff --git a/fastlane/metadata/android/ru-RU/changelogs/40104080.txt b/fastlane/metadata/android/ru-RU/changelogs/40104080.txt
new file mode 100644
index 0000000000..faa12f093b
--- /dev/null
+++ b/fastlane/metadata/android/ru-RU/changelogs/40104080.txt
@@ -0,0 +1,2 @@
+Основные изменения в этой версии: Лента веток работает в реальном времени и быстрее. Различные исправления ошибок и улучшения стабильности.
+Полный список изменений: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/ru-RU/changelogs/40104100.txt b/fastlane/metadata/android/ru-RU/changelogs/40104100.txt
new file mode 100644
index 0000000000..853c7aabec
--- /dev/null
+++ b/fastlane/metadata/android/ru-RU/changelogs/40104100.txt
@@ -0,0 +1,2 @@
+Основные изменения в этой версии: Прокрутка голосовых сообщений. Различные исправления ошибок и улучшения стабильности.
+Полный список изменений: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/ru-RU/changelogs/40104110.txt b/fastlane/metadata/android/ru-RU/changelogs/40104110.txt
new file mode 100644
index 0000000000..31cc5effa6
--- /dev/null
+++ b/fastlane/metadata/android/ru-RU/changelogs/40104110.txt
@@ -0,0 +1,2 @@
+Основные изменения в этой версии: Различные исправления ошибок и улучшения стабильности.
+Полный список изменений: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/ru-RU/changelogs/40104120.txt b/fastlane/metadata/android/ru-RU/changelogs/40104120.txt
new file mode 100644
index 0000000000..0dc35fac76
--- /dev/null
+++ b/fastlane/metadata/android/ru-RU/changelogs/40104120.txt
@@ -0,0 +1,2 @@
+Основные изменения в этой версии: Позволяет пользователям появляться в автономном режиме и добавляет аудиопроигрыватель для аудиовложений
+Полный список изменений: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/ru-RU/changelogs/40104130.txt b/fastlane/metadata/android/ru-RU/changelogs/40104130.txt
new file mode 100644
index 0000000000..3eec4c4987
--- /dev/null
+++ b/fastlane/metadata/android/ru-RU/changelogs/40104130.txt
@@ -0,0 +1,2 @@
+Основные изменения в этой версии: Позволяет пользователям появляться в автономном режиме и добавляет аудиопроигрыватель для аудиовложений.
+Полный список изменений: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/ru-RU/changelogs/40104140.txt b/fastlane/metadata/android/ru-RU/changelogs/40104140.txt
new file mode 100644
index 0000000000..dcb6d19cbf
--- /dev/null
+++ b/fastlane/metadata/android/ru-RU/changelogs/40104140.txt
@@ -0,0 +1,2 @@
+Основные изменения в этой версии: Улучшено управление игнорируемыми пользователями. Различные исправления ошибок и улучшения стабильности.
+Полный список изменений: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/ru-RU/changelogs/40104160.txt b/fastlane/metadata/android/ru-RU/changelogs/40104160.txt
new file mode 100644
index 0000000000..ea8f0f84cb
--- /dev/null
+++ b/fastlane/metadata/android/ru-RU/changelogs/40104160.txt
@@ -0,0 +1,2 @@
+Основные изменения в этой версии: Улучшено управление зашифрованными сообщениями. Различные исправления ошибок и улучшения стабильности.
+Полный список изменений: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/ru-RU/changelogs/40104180.txt b/fastlane/metadata/android/ru-RU/changelogs/40104180.txt
new file mode 100644
index 0000000000..31cc5effa6
--- /dev/null
+++ b/fastlane/metadata/android/ru-RU/changelogs/40104180.txt
@@ -0,0 +1,2 @@
+Основные изменения в этой версии: Различные исправления ошибок и улучшения стабильности.
+Полный список изменений: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/ru-RU/changelogs/40104190.txt b/fastlane/metadata/android/ru-RU/changelogs/40104190.txt
new file mode 100644
index 0000000000..31cc5effa6
--- /dev/null
+++ b/fastlane/metadata/android/ru-RU/changelogs/40104190.txt
@@ -0,0 +1,2 @@
+Основные изменения в этой версии: Различные исправления ошибок и улучшения стабильности.
+Полный список изменений: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/ru-RU/changelogs/40104200.txt b/fastlane/metadata/android/ru-RU/changelogs/40104200.txt
new file mode 100644
index 0000000000..31cc5effa6
--- /dev/null
+++ b/fastlane/metadata/android/ru-RU/changelogs/40104200.txt
@@ -0,0 +1,2 @@
+Основные изменения в этой версии: Различные исправления ошибок и улучшения стабильности.
+Полный список изменений: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/ru-RU/changelogs/40104220.txt b/fastlane/metadata/android/ru-RU/changelogs/40104220.txt
new file mode 100644
index 0000000000..31cc5effa6
--- /dev/null
+++ b/fastlane/metadata/android/ru-RU/changelogs/40104220.txt
@@ -0,0 +1,2 @@
+Основные изменения в этой версии: Различные исправления ошибок и улучшения стабильности.
+Полный список изменений: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/ru-RU/changelogs/40104230.txt b/fastlane/metadata/android/ru-RU/changelogs/40104230.txt
new file mode 100644
index 0000000000..31cc5effa6
--- /dev/null
+++ b/fastlane/metadata/android/ru-RU/changelogs/40104230.txt
@@ -0,0 +1,2 @@
+Основные изменения в этой версии: Различные исправления ошибок и улучшения стабильности.
+Полный список изменений: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/ru-RU/changelogs/40104240.txt b/fastlane/metadata/android/ru-RU/changelogs/40104240.txt
new file mode 100644
index 0000000000..31cc5effa6
--- /dev/null
+++ b/fastlane/metadata/android/ru-RU/changelogs/40104240.txt
@@ -0,0 +1,2 @@
+Основные изменения в этой версии: Различные исправления ошибок и улучшения стабильности.
+Полный список изменений: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/ru-RU/changelogs/40104250.txt b/fastlane/metadata/android/ru-RU/changelogs/40104250.txt
new file mode 100644
index 0000000000..57c0128d34
--- /dev/null
+++ b/fastlane/metadata/android/ru-RU/changelogs/40104250.txt
@@ -0,0 +1,2 @@
+Основные изменения в этой версии: исправлены известные проблемы и улучшена стабильность.
+Полный список изменений: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/ru-RU/full_description.txt b/fastlane/metadata/android/ru-RU/full_description.txt
index 3d8949e466..b2320d9f0b 100644
--- a/fastlane/metadata/android/ru-RU/full_description.txt
+++ b/fastlane/metadata/android/ru-RU/full_description.txt
@@ -40,4 +40,4 @@ Element дает вам возможность контролировать си
Открытый исходный код
-Element Android - это проект с открытым исходным кодом, размещенный на GitHub. Пожалуйста, сообщайте об ошибках и/или вносите вклад в его развитие по адресу https://github.com/vector-im/element-android.
+Element Android - это проект с открытым исходным кодом, размещенный на GitHub. Пожалуйста, сообщайте об ошибках и/или вносите вклад в его развитие по адресу https://github.com/vector-im/element-android
diff --git a/fastlane/metadata/android/sk/changelogs/40104160.txt b/fastlane/metadata/android/sk/changelogs/40104160.txt
new file mode 100644
index 0000000000..e6e2f45c32
--- /dev/null
+++ b/fastlane/metadata/android/sk/changelogs/40104160.txt
@@ -0,0 +1,2 @@
+Hlavné zmeny v tejto verzii: Lepšia spravovanie zašifrovaných správ. Rôzne opravy chýb a vylepšenia stability.
+Úplný zoznam zmien: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/sk/changelogs/40104180.txt b/fastlane/metadata/android/sk/changelogs/40104180.txt
new file mode 100644
index 0000000000..50670f18c2
--- /dev/null
+++ b/fastlane/metadata/android/sk/changelogs/40104180.txt
@@ -0,0 +1,2 @@
+Hlavné zmeny v tejto verzii: Rôzne opravy chýb a vylepšenia stability.
+Úplný zoznam zmien: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/sk/changelogs/40104190.txt b/fastlane/metadata/android/sk/changelogs/40104190.txt
new file mode 100644
index 0000000000..50670f18c2
--- /dev/null
+++ b/fastlane/metadata/android/sk/changelogs/40104190.txt
@@ -0,0 +1,2 @@
+Hlavné zmeny v tejto verzii: Rôzne opravy chýb a vylepšenia stability.
+Úplný zoznam zmien: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/sk/changelogs/40104200.txt b/fastlane/metadata/android/sk/changelogs/40104200.txt
new file mode 100644
index 0000000000..50670f18c2
--- /dev/null
+++ b/fastlane/metadata/android/sk/changelogs/40104200.txt
@@ -0,0 +1,2 @@
+Hlavné zmeny v tejto verzii: Rôzne opravy chýb a vylepšenia stability.
+Úplný zoznam zmien: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/sk/changelogs/40104220.txt b/fastlane/metadata/android/sk/changelogs/40104220.txt
new file mode 100644
index 0000000000..50670f18c2
--- /dev/null
+++ b/fastlane/metadata/android/sk/changelogs/40104220.txt
@@ -0,0 +1,2 @@
+Hlavné zmeny v tejto verzii: Rôzne opravy chýb a vylepšenia stability.
+Úplný zoznam zmien: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/sk/changelogs/40104230.txt b/fastlane/metadata/android/sk/changelogs/40104230.txt
new file mode 100644
index 0000000000..50670f18c2
--- /dev/null
+++ b/fastlane/metadata/android/sk/changelogs/40104230.txt
@@ -0,0 +1,2 @@
+Hlavné zmeny v tejto verzii: Rôzne opravy chýb a vylepšenia stability.
+Úplný zoznam zmien: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/sk/changelogs/40104240.txt b/fastlane/metadata/android/sk/changelogs/40104240.txt
new file mode 100644
index 0000000000..50670f18c2
--- /dev/null
+++ b/fastlane/metadata/android/sk/changelogs/40104240.txt
@@ -0,0 +1,2 @@
+Hlavné zmeny v tejto verzii: Rôzne opravy chýb a vylepšenia stability.
+Úplný zoznam zmien: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/sk/changelogs/40104250.txt b/fastlane/metadata/android/sk/changelogs/40104250.txt
new file mode 100644
index 0000000000..50670f18c2
--- /dev/null
+++ b/fastlane/metadata/android/sk/changelogs/40104250.txt
@@ -0,0 +1,2 @@
+Hlavné zmeny v tejto verzii: Rôzne opravy chýb a vylepšenia stability.
+Úplný zoznam zmien: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/sk/changelogs/40104260.txt b/fastlane/metadata/android/sk/changelogs/40104260.txt
new file mode 100644
index 0000000000..6980671174
--- /dev/null
+++ b/fastlane/metadata/android/sk/changelogs/40104260.txt
@@ -0,0 +1,2 @@
+Hlavné zmeny v tejto verzii: Použitie UnifiedPush a umožňuje používateľovi používať push bez FCM.
+Úplný zoznam zmien: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/sk/changelogs/40104270.txt b/fastlane/metadata/android/sk/changelogs/40104270.txt
new file mode 100644
index 0000000000..50670f18c2
--- /dev/null
+++ b/fastlane/metadata/android/sk/changelogs/40104270.txt
@@ -0,0 +1,2 @@
+Hlavné zmeny v tejto verzii: Rôzne opravy chýb a vylepšenia stability.
+Úplný zoznam zmien: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/sk/changelogs/40104280.txt b/fastlane/metadata/android/sk/changelogs/40104280.txt
new file mode 100644
index 0000000000..50670f18c2
--- /dev/null
+++ b/fastlane/metadata/android/sk/changelogs/40104280.txt
@@ -0,0 +1,2 @@
+Hlavné zmeny v tejto verzii: Rôzne opravy chýb a vylepšenia stability.
+Úplný zoznam zmien: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/sv-SE/changelogs/40104160.txt b/fastlane/metadata/android/sv-SE/changelogs/40104160.txt
new file mode 100644
index 0000000000..cf7eda6ef8
--- /dev/null
+++ b/fastlane/metadata/android/sv-SE/changelogs/40104160.txt
@@ -0,0 +1,2 @@
+Huvudsakliga ändringar i den här versionen: Bättre hantering av krypterade meddelanden. Diverse buggfixar och stabilitetsförbättringar.
+Full ändringslogg: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/sv-SE/changelogs/40104180.txt b/fastlane/metadata/android/sv-SE/changelogs/40104180.txt
new file mode 100644
index 0000000000..d8db452b51
--- /dev/null
+++ b/fastlane/metadata/android/sv-SE/changelogs/40104180.txt
@@ -0,0 +1,2 @@
+Huvudsakliga ändringar i den här versionen: Diverse buggfixar och stabilitetsförbättringar.
+Full ändringslogg: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/sv-SE/changelogs/40104190.txt b/fastlane/metadata/android/sv-SE/changelogs/40104190.txt
new file mode 100644
index 0000000000..d8db452b51
--- /dev/null
+++ b/fastlane/metadata/android/sv-SE/changelogs/40104190.txt
@@ -0,0 +1,2 @@
+Huvudsakliga ändringar i den här versionen: Diverse buggfixar och stabilitetsförbättringar.
+Full ändringslogg: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/sv-SE/changelogs/40104200.txt b/fastlane/metadata/android/sv-SE/changelogs/40104200.txt
new file mode 100644
index 0000000000..d8db452b51
--- /dev/null
+++ b/fastlane/metadata/android/sv-SE/changelogs/40104200.txt
@@ -0,0 +1,2 @@
+Huvudsakliga ändringar i den här versionen: Diverse buggfixar och stabilitetsförbättringar.
+Full ändringslogg: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/sv-SE/changelogs/40104220.txt b/fastlane/metadata/android/sv-SE/changelogs/40104220.txt
new file mode 100644
index 0000000000..d8db452b51
--- /dev/null
+++ b/fastlane/metadata/android/sv-SE/changelogs/40104220.txt
@@ -0,0 +1,2 @@
+Huvudsakliga ändringar i den här versionen: Diverse buggfixar och stabilitetsförbättringar.
+Full ändringslogg: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/sv-SE/changelogs/40104230.txt b/fastlane/metadata/android/sv-SE/changelogs/40104230.txt
new file mode 100644
index 0000000000..d8db452b51
--- /dev/null
+++ b/fastlane/metadata/android/sv-SE/changelogs/40104230.txt
@@ -0,0 +1,2 @@
+Huvudsakliga ändringar i den här versionen: Diverse buggfixar och stabilitetsförbättringar.
+Full ändringslogg: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/sv-SE/changelogs/40104240.txt b/fastlane/metadata/android/sv-SE/changelogs/40104240.txt
new file mode 100644
index 0000000000..d8db452b51
--- /dev/null
+++ b/fastlane/metadata/android/sv-SE/changelogs/40104240.txt
@@ -0,0 +1,2 @@
+Huvudsakliga ändringar i den här versionen: Diverse buggfixar och stabilitetsförbättringar.
+Full ändringslogg: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/sv-SE/changelogs/40104250.txt b/fastlane/metadata/android/sv-SE/changelogs/40104250.txt
new file mode 100644
index 0000000000..d8db452b51
--- /dev/null
+++ b/fastlane/metadata/android/sv-SE/changelogs/40104250.txt
@@ -0,0 +1,2 @@
+Huvudsakliga ändringar i den här versionen: Diverse buggfixar och stabilitetsförbättringar.
+Full ändringslogg: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/sv-SE/changelogs/40104260.txt b/fastlane/metadata/android/sv-SE/changelogs/40104260.txt
new file mode 100644
index 0000000000..99185d8562
--- /dev/null
+++ b/fastlane/metadata/android/sv-SE/changelogs/40104260.txt
@@ -0,0 +1,2 @@
+Huvudsakliga ändringar i den här versionen: Använd UnifiedPush och tillåt användare att ha push utan FCM.
+Full ändringslogg: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/sv-SE/changelogs/40104270.txt b/fastlane/metadata/android/sv-SE/changelogs/40104270.txt
new file mode 100644
index 0000000000..d8db452b51
--- /dev/null
+++ b/fastlane/metadata/android/sv-SE/changelogs/40104270.txt
@@ -0,0 +1,2 @@
+Huvudsakliga ändringar i den här versionen: Diverse buggfixar och stabilitetsförbättringar.
+Full ändringslogg: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/sv-SE/changelogs/40104280.txt b/fastlane/metadata/android/sv-SE/changelogs/40104280.txt
new file mode 100644
index 0000000000..d8db452b51
--- /dev/null
+++ b/fastlane/metadata/android/sv-SE/changelogs/40104280.txt
@@ -0,0 +1,2 @@
+Huvudsakliga ändringar i den här versionen: Diverse buggfixar och stabilitetsförbättringar.
+Full ändringslogg: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/ta-IN/title.txt b/fastlane/metadata/android/ta-IN/title.txt
index ecb9a01c06..907f907f99 100644
--- a/fastlane/metadata/android/ta-IN/title.txt
+++ b/fastlane/metadata/android/ta-IN/title.txt
@@ -1 +1 @@
-Element - பாதுகாப்பான தூதுரை சேவை
+Element
diff --git a/fastlane/metadata/android/uk/changelogs/40101000.txt b/fastlane/metadata/android/uk/changelogs/40101000.txt
index 36870f5ef7..1b7d25f1b9 100644
--- a/fastlane/metadata/android/uk/changelogs/40101000.txt
+++ b/fastlane/metadata/android/uk/changelogs/40101000.txt
@@ -1,2 +1,2 @@
-Основні зміни в цій версії: поліпшення VoIP (аудіо та відео дзвінки в DM) та виправлення помилок!
+Основні зміни в цій версії: поліпшення VoIP (аудіо та відеовиклики у ПП) та виправлення помилок!
Повний журнал змін: https://github.com/vector-im/element-android/releases/tag/v1.1.0
diff --git a/fastlane/metadata/android/uk/changelogs/40104000.txt b/fastlane/metadata/android/uk/changelogs/40104000.txt
index 6abfdcf929..b4203b0e3f 100644
--- a/fastlane/metadata/android/uk/changelogs/40104000.txt
+++ b/fastlane/metadata/android/uk/changelogs/40104000.txt
@@ -1,2 +1,2 @@
-Основні зміни в цій версії: Початкова реалізація тредів повідомлень. Повідомлення бульбашки.
+Основні зміни в цій версії: Початкова реалізація гілок повідомлень. Повідомлення бульбашки.
Вичерпний перелік змін: https://github.com/vector-im/element-android/releases/tag/v1.4.0
diff --git a/fastlane/metadata/android/uk/changelogs/40104060.txt b/fastlane/metadata/android/uk/changelogs/40104060.txt
index 28f051724a..a5dac44be2 100644
--- a/fastlane/metadata/android/uk/changelogs/40104060.txt
+++ b/fastlane/metadata/android/uk/changelogs/40104060.txt
@@ -1,2 +1,2 @@
-Основні зміни в цій версії: Хронологія тредів працює наживо і швидше. Усунуто різні вади й поліпшено стабільність.
+Основні зміни в цій версії: Хронологія гілок працює наживо і швидше. Усунуто різні вади й поліпшено стабільність.
Вичерпний перелік змін: https://github.com/vector-im/element-android/releases/tag/v1.4.6
diff --git a/fastlane/metadata/android/uk/changelogs/40104080.txt b/fastlane/metadata/android/uk/changelogs/40104080.txt
index e5f7e7b271..5155793561 100644
--- a/fastlane/metadata/android/uk/changelogs/40104080.txt
+++ b/fastlane/metadata/android/uk/changelogs/40104080.txt
@@ -1,2 +1,2 @@
-Основні зміни в цій версії: Хронологія тредів працює наживо і швидше. Усунуто різні вади й поліпшено стабільність.
+Основні зміни в цій версії: Хронологія гілок працює наживо і швидше. Усунуто різні вади й поліпшено стабільність.
Вичерпний перелік змін: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/uk/changelogs/40104160.txt b/fastlane/metadata/android/uk/changelogs/40104160.txt
new file mode 100644
index 0000000000..33ad65f75c
--- /dev/null
+++ b/fastlane/metadata/android/uk/changelogs/40104160.txt
@@ -0,0 +1,2 @@
+Основні зміни в цій версії: Поліпшено керування зашифрованими повідомленнями. Усунуто різні вади й поліпшено стабільність.
+Вичерпний перелік змін: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/uk/changelogs/40104180.txt b/fastlane/metadata/android/uk/changelogs/40104180.txt
new file mode 100644
index 0000000000..252a57c9d9
--- /dev/null
+++ b/fastlane/metadata/android/uk/changelogs/40104180.txt
@@ -0,0 +1,2 @@
+Основні зміни в цій версії: Усунуто різні вади й поліпшено стабільність.
+Вичерпний перелік змін: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/uk/changelogs/40104190.txt b/fastlane/metadata/android/uk/changelogs/40104190.txt
new file mode 100644
index 0000000000..252a57c9d9
--- /dev/null
+++ b/fastlane/metadata/android/uk/changelogs/40104190.txt
@@ -0,0 +1,2 @@
+Основні зміни в цій версії: Усунуто різні вади й поліпшено стабільність.
+Вичерпний перелік змін: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/uk/changelogs/40104200.txt b/fastlane/metadata/android/uk/changelogs/40104200.txt
new file mode 100644
index 0000000000..252a57c9d9
--- /dev/null
+++ b/fastlane/metadata/android/uk/changelogs/40104200.txt
@@ -0,0 +1,2 @@
+Основні зміни в цій версії: Усунуто різні вади й поліпшено стабільність.
+Вичерпний перелік змін: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/uk/changelogs/40104220.txt b/fastlane/metadata/android/uk/changelogs/40104220.txt
new file mode 100644
index 0000000000..252a57c9d9
--- /dev/null
+++ b/fastlane/metadata/android/uk/changelogs/40104220.txt
@@ -0,0 +1,2 @@
+Основні зміни в цій версії: Усунуто різні вади й поліпшено стабільність.
+Вичерпний перелік змін: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/uk/changelogs/40104230.txt b/fastlane/metadata/android/uk/changelogs/40104230.txt
new file mode 100644
index 0000000000..252a57c9d9
--- /dev/null
+++ b/fastlane/metadata/android/uk/changelogs/40104230.txt
@@ -0,0 +1,2 @@
+Основні зміни в цій версії: Усунуто різні вади й поліпшено стабільність.
+Вичерпний перелік змін: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/uk/changelogs/40104240.txt b/fastlane/metadata/android/uk/changelogs/40104240.txt
new file mode 100644
index 0000000000..252a57c9d9
--- /dev/null
+++ b/fastlane/metadata/android/uk/changelogs/40104240.txt
@@ -0,0 +1,2 @@
+Основні зміни в цій версії: Усунуто різні вади й поліпшено стабільність.
+Вичерпний перелік змін: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/uk/changelogs/40104250.txt b/fastlane/metadata/android/uk/changelogs/40104250.txt
new file mode 100644
index 0000000000..252a57c9d9
--- /dev/null
+++ b/fastlane/metadata/android/uk/changelogs/40104250.txt
@@ -0,0 +1,2 @@
+Основні зміни в цій версії: Усунуто різні вади й поліпшено стабільність.
+Вичерпний перелік змін: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/uk/changelogs/40104260.txt b/fastlane/metadata/android/uk/changelogs/40104260.txt
new file mode 100644
index 0000000000..3e3219946a
--- /dev/null
+++ b/fastlane/metadata/android/uk/changelogs/40104260.txt
@@ -0,0 +1,2 @@
+Основні зміни в цій версії: Застосовано UnifiedPush і дозволено користувачам отримувати push-сповіщення без FCM.
+Перелік усіх змін: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/uk/changelogs/40104270.txt b/fastlane/metadata/android/uk/changelogs/40104270.txt
new file mode 100644
index 0000000000..9664c615c1
--- /dev/null
+++ b/fastlane/metadata/android/uk/changelogs/40104270.txt
@@ -0,0 +1,2 @@
+Основні зміни в цій версії: Усунуто різні вади й поліпшено стабільність.
+Перелік усіх змін: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/uk/changelogs/40104280.txt b/fastlane/metadata/android/uk/changelogs/40104280.txt
new file mode 100644
index 0000000000..82eef725e0
--- /dev/null
+++ b/fastlane/metadata/android/uk/changelogs/40104280.txt
@@ -0,0 +1,2 @@
+Основні зміни в цій версії: Усунуто різні вади й поліпшено стабільність.
+Перелік усіх змін://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/zh-CN/changelogs/40100120.txt b/fastlane/metadata/android/zh-CN/changelogs/40100120.txt
index 67d69a3834..10c251531d 100644
--- a/fastlane/metadata/android/zh-CN/changelogs/40100120.txt
+++ b/fastlane/metadata/android/zh-CN/changelogs/40100120.txt
@@ -1,2 +1,2 @@
-此版本的主要变化:链接预览,全新 Emoji 键盘,全新聊天室设置功能,以及圣诞节雪花!
+此版本的主要变化:链接预览,全新 Emoji 键盘,全新房间设置功能,以及圣诞节雪花!
完整更新日志:https://github.com/vector-im/element-android/releases/tag/v1.0.12
diff --git a/fastlane/metadata/android/zh-CN/changelogs/40100130.txt b/fastlane/metadata/android/zh-CN/changelogs/40100130.txt
index 5a2ba4256f..18c8d466e5 100644
--- a/fastlane/metadata/android/zh-CN/changelogs/40100130.txt
+++ b/fastlane/metadata/android/zh-CN/changelogs/40100130.txt
@@ -1,2 +1,2 @@
-此版本的主要变化:链接预览,全新 Emoji 键盘,全新聊天室设置功能,以及圣诞节雪花!
+此版本的主要变化:链接预览,全新 Emoji 键盘,全新房间设置功能,以及圣诞节雪花!
完整更新日志:https://github.com/vector-im/element-android/releases/tag/v1.0.13
diff --git a/fastlane/metadata/android/zh-CN/changelogs/40100140.txt b/fastlane/metadata/android/zh-CN/changelogs/40100140.txt
index dc25b5094b..82726e22c3 100644
--- a/fastlane/metadata/android/zh-CN/changelogs/40100140.txt
+++ b/fastlane/metadata/android/zh-CN/changelogs/40100140.txt
@@ -1,2 +1,2 @@
-此版本的主要变化:支持编辑聊天室权限,自动切换浅色/深色主题,修复大量错误。
+此版本的主要变化:支持编辑房间权限,自动切换浅色/深色主题,修复大量错误。
完整更新日志:https://github.com/vector-im/element-android/releases/tag/v1.0.14
diff --git a/fastlane/metadata/android/zh-CN/changelogs/40101160.txt b/fastlane/metadata/android/zh-CN/changelogs/40101160.txt
index 98357b0dc5..16f38a0d49 100644
--- a/fastlane/metadata/android/zh-CN/changelogs/40101160.txt
+++ b/fastlane/metadata/android/zh-CN/changelogs/40101160.txt
@@ -1,2 +1,2 @@
-此版本的主要变化:修复聊天室中有人登出时发送加密消息所遇到的错误。
+此版本的主要变化:修复房间中有人登出时发送加密消息所遇到的错误。
完整更新日志:https://github.com/vector-im/element-android/releases/tag/v1.1.16
diff --git a/fastlane/metadata/android/zh-CN/changelogs/40103000.txt b/fastlane/metadata/android/zh-CN/changelogs/40103000.txt
index 96ec8b3322..6d0917a3f0 100644
--- a/fastlane/metadata/android/zh-CN/changelogs/40103000.txt
+++ b/fastlane/metadata/android/zh-CN/changelogs/40103000.txt
@@ -1,2 +1,2 @@
-此版本主要更改:使用空间组织你的聊天室!
+此版本主要更改:使用空间组织你的房间!
完整更新日志:https://github.com/vector-im/element-android/releases/tag/v1.3.0
diff --git a/fastlane/metadata/android/zh-CN/changelogs/40103010.txt b/fastlane/metadata/android/zh-CN/changelogs/40103010.txt
index 98b506fb6e..0c36f40e1d 100644
--- a/fastlane/metadata/android/zh-CN/changelogs/40103010.txt
+++ b/fastlane/metadata/android/zh-CN/changelogs/40103010.txt
@@ -1,2 +1,2 @@
-此版本的主要变化:使用空间组织您的聊天室! v1.3.1 正在修复 v1.3.0 中可能发生的崩溃。
+此版本的主要变化:使用空间组织您的房间! v1.3.1 正在修复 v1.3.0 中可能发生的崩溃。
完整更新日志:https://github.com/vector-im/element-android/releases/tag/v1.3.1
diff --git a/fastlane/metadata/android/zh-CN/changelogs/40103040.txt b/fastlane/metadata/android/zh-CN/changelogs/40103040.txt
index c879c3d036..a11c32b773 100644
--- a/fastlane/metadata/android/zh-CN/changelogs/40103040.txt
+++ b/fastlane/metadata/android/zh-CN/changelogs/40103040.txt
@@ -1,2 +1,2 @@
-此版本主要变化:为 Direct Message 聊天室添加 Presence 支持 (注意:presence 在 matrix.org 上是禁用的)。再次添加 Android Auto 支持。
+此版本主要变化:为 Direct Message 房间添加 Presence 支持 (注意:presence 在 matrix.org 上是禁用的)。再次添加 Android Auto 支持。
完整更新日志:https://github.com/vector-im/element-android/releases/tag/v1.3.4
diff --git a/fastlane/metadata/android/zh-CN/changelogs/40103050.txt b/fastlane/metadata/android/zh-CN/changelogs/40103050.txt
index 7343ae0b9f..537964320a 100644
--- a/fastlane/metadata/android/zh-CN/changelogs/40103050.txt
+++ b/fastlane/metadata/android/zh-CN/changelogs/40103050.txt
@@ -1,2 +1,2 @@
-此版本的主要变化:为私信聊天室添加 Presence 支持 (注意:在 matrix.org 上 Presence 是禁用的)。再次添加 Android Auto 支持。
+此版本的主要变化:为私信房间添加 Presence 支持 (注意:在 matrix.org 上 Presence 是禁用的)。再次添加 Android Auto 支持。
完整更新日志:https://github.com/vector-im/element-android/releases/tag/v1.3.5
diff --git a/fastlane/metadata/android/zh-CN/changelogs/40103060.txt b/fastlane/metadata/android/zh-CN/changelogs/40103060.txt
index 8322539927..7621ec3870 100644
--- a/fastlane/metadata/android/zh-CN/changelogs/40103060.txt
+++ b/fastlane/metadata/android/zh-CN/changelogs/40103060.txt
@@ -1,2 +1,2 @@
-此版本的主要变化:为私信聊天室添加 Presence 支持(注意:在 matrix.org 上 Presence 是禁用的)。再次添加 Android Auto 支持。
+此版本的主要变化:为私信房间添加 Presence 支持(注意:在 matrix.org 上 Presence 是禁用的)。再次添加 Android Auto 支持。
完整更新日志:https://github.com/vector-im/element-android/releases/tag/v1.3.6
diff --git a/fastlane/metadata/android/zh-CN/changelogs/40103100.txt b/fastlane/metadata/android/zh-CN/changelogs/40103100.txt
new file mode 100644
index 0000000000..7f17f68a1d
--- /dev/null
+++ b/fastlane/metadata/android/zh-CN/changelogs/40103100.txt
@@ -0,0 +1,2 @@
+此版本的主要变化:新增对投票(在实验室中)的支持。新的URL预览设计。
+完整更改日志:https://github.com/vector-im/element-android/releases/tag/v1.3.10
diff --git a/fastlane/metadata/android/zh-CN/changelogs/40103110.txt b/fastlane/metadata/android/zh-CN/changelogs/40103110.txt
new file mode 100644
index 0000000000..cfa0ae74be
--- /dev/null
+++ b/fastlane/metadata/android/zh-CN/changelogs/40103110.txt
@@ -0,0 +1,2 @@
+此版本的主要变化:bug修复!
+完整更改日志:https://github.com/vector-im/element-android/releases/tag/v1.3.11
diff --git a/fastlane/metadata/android/zh-CN/changelogs/40103120.txt b/fastlane/metadata/android/zh-CN/changelogs/40103120.txt
new file mode 100644
index 0000000000..c0b5935928
--- /dev/null
+++ b/fastlane/metadata/android/zh-CN/changelogs/40103120.txt
@@ -0,0 +1,2 @@
+此版本的主要变化:bug修复!
+完整更新日志:https://github.com/vector-im/element-android/releases/tag/v1.3.12
diff --git a/fastlane/metadata/android/zh-CN/changelogs/40103130.txt b/fastlane/metadata/android/zh-CN/changelogs/40103130.txt
new file mode 100644
index 0000000000..f8fff1b33d
--- /dev/null
+++ b/fastlane/metadata/android/zh-CN/changelogs/40103130.txt
@@ -0,0 +1,2 @@
+此版本的主要变化:First change in onboarding screens, including Analytics opt-in. 对添加在实验中带有数学的事件的支持。
+完整更改日志:https://github.com/vector-im/element-android/releases/tag/v1.3.13
diff --git a/fastlane/metadata/android/zh-CN/changelogs/40103140.txt b/fastlane/metadata/android/zh-CN/changelogs/40103140.txt
new file mode 100644
index 0000000000..c035e13025
--- /dev/null
+++ b/fastlane/metadata/android/zh-CN/changelogs/40103140.txt
@@ -0,0 +1,2 @@
+此版本的主要变化:First change in onboarding screens, including Analytics opt-in. 对添加在实验中带有数学的事件的支持。
+完整更改日志:https://github.com/vector-im/element-android/releases/tag/v1.3.14
diff --git a/fastlane/metadata/android/zh-CN/changelogs/40103150.txt b/fastlane/metadata/android/zh-CN/changelogs/40103150.txt
new file mode 100644
index 0000000000..f5edd7ab4d
--- /dev/null
+++ b/fastlane/metadata/android/zh-CN/changelogs/40103150.txt
@@ -0,0 +1,2 @@
+此版本的主要变化:对新用户引导画面的首次更改,包括选择加入分析的功能。对添加在实验中带有数学的事件的支持。
+完整更改日志:https://github.com/vector-im/element-android/releases/tag/v1.3.15
diff --git a/fastlane/metadata/android/zh-CN/changelogs/40103160.txt b/fastlane/metadata/android/zh-CN/changelogs/40103160.txt
new file mode 100644
index 0000000000..8bed014719
--- /dev/null
+++ b/fastlane/metadata/android/zh-CN/changelogs/40103160.txt
@@ -0,0 +1,2 @@
+此版本的主要变化:给任何房间发送你的位置。编辑投票。
+完整更改日志:https://github.com/vector-im/element-android/releases/tag/v1.3.16
diff --git a/fastlane/metadata/android/zh-CN/changelogs/40103170.txt b/fastlane/metadata/android/zh-CN/changelogs/40103170.txt
new file mode 100644
index 0000000000..ad6c6c8702
--- /dev/null
+++ b/fastlane/metadata/android/zh-CN/changelogs/40103170.txt
@@ -0,0 +1,2 @@
+此版本的主要变化:给任何房间发送你的位置。编辑投票。
+完整更改日志:https://github.com/vector-im/element-android/releases/tag/v1.3.17
diff --git a/fastlane/metadata/android/zh-CN/changelogs/40103180.txt b/fastlane/metadata/android/zh-CN/changelogs/40103180.txt
new file mode 100644
index 0000000000..1db4de49c3
--- /dev/null
+++ b/fastlane/metadata/android/zh-CN/changelogs/40103180.txt
@@ -0,0 +1,2 @@
+此版本的主要变化:给任何房间发送你的位置。编辑投票。
+完整更改日志:https://github.com/vector-im/element-android/releases/tag/v1.3.18
diff --git a/fastlane/metadata/android/zh-CN/changelogs/40104000.txt b/fastlane/metadata/android/zh-CN/changelogs/40104000.txt
new file mode 100644
index 0000000000..6a93e2b20b
--- /dev/null
+++ b/fastlane/metadata/android/zh-CN/changelogs/40104000.txt
@@ -0,0 +1,2 @@
+此版本的主要变化:消息列的初始实现。消息气泡。
+完整更改日志:https://github.com/vector-im/element-android/releases/tag/v1.4.0
diff --git a/fastlane/metadata/android/zh-CN/changelogs/40104020.txt b/fastlane/metadata/android/zh-CN/changelogs/40104020.txt
new file mode 100644
index 0000000000..785c09f02a
--- /dev/null
+++ b/fastlane/metadata/android/zh-CN/changelogs/40104020.txt
@@ -0,0 +1,2 @@
+此版本的主要变化:新增对@room和未公开的投票的支持,还有许多其它小改动。
+完整更改日志:https://github.com/vector-im/element-android/releases/tag/v1.4.2
diff --git a/fastlane/metadata/android/zh-CN/changelogs/40104040.txt b/fastlane/metadata/android/zh-CN/changelogs/40104040.txt
new file mode 100644
index 0000000000..aafaad4a7c
--- /dev/null
+++ b/fastlane/metadata/android/zh-CN/changelogs/40104040.txt
@@ -0,0 +1,2 @@
+此版本的主要变化:输入指示器UI更新。多个bug修复及稳定性改进。
+完整更改日志:https://github.com/vector-im/element-android/releases/tag/v1.4.4
diff --git a/fastlane/metadata/android/zh-CN/changelogs/40104060.txt b/fastlane/metadata/android/zh-CN/changelogs/40104060.txt
new file mode 100644
index 0000000000..5c57abccbd
--- /dev/null
+++ b/fastlane/metadata/android/zh-CN/changelogs/40104060.txt
@@ -0,0 +1,2 @@
+此版本的主要变化:Thread timeline are now live and faster. 多个bug修复及稳定性改进。
+完整更改日志:https://github.com/vector-im/element-android/releases/tag/v1.4.6
diff --git a/fastlane/metadata/android/zh-CN/changelogs/40104070.txt b/fastlane/metadata/android/zh-CN/changelogs/40104070.txt
new file mode 100644
index 0000000000..c7b363a320
--- /dev/null
+++ b/fastlane/metadata/android/zh-CN/changelogs/40104070.txt
@@ -0,0 +1,2 @@
+此版本的主要变化:多个bug修复及稳定性改进。
+完整更改日志:https://github.com/vector-im/element-android/releases/tag/v1.4.7
diff --git a/fastlane/metadata/android/zh-CN/changelogs/40104080.txt b/fastlane/metadata/android/zh-CN/changelogs/40104080.txt
new file mode 100644
index 0000000000..44d178cfce
--- /dev/null
+++ b/fastlane/metadata/android/zh-CN/changelogs/40104080.txt
@@ -0,0 +1,2 @@
+此版本的主要变化:Thread timeline are now live and faster. 多个bug修复及稳定性改进。
+完整更改日志:https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/zh-CN/changelogs/40104100.txt b/fastlane/metadata/android/zh-CN/changelogs/40104100.txt
new file mode 100644
index 0000000000..0c51c9325a
--- /dev/null
+++ b/fastlane/metadata/android/zh-CN/changelogs/40104100.txt
@@ -0,0 +1,2 @@
+此版本的主要变化:在语音消息中拖动。多个bug修复及稳定性改进。
+完整更改日志:https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/zh-CN/changelogs/40104110.txt b/fastlane/metadata/android/zh-CN/changelogs/40104110.txt
new file mode 100644
index 0000000000..b2c236dc31
--- /dev/null
+++ b/fastlane/metadata/android/zh-CN/changelogs/40104110.txt
@@ -0,0 +1,2 @@
+此版本的主要变化:多个bug修复及稳定性改进。
+完整更改日志:https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/zh-CN/changelogs/40104120.txt b/fastlane/metadata/android/zh-CN/changelogs/40104120.txt
new file mode 100644
index 0000000000..c0b39f3f92
--- /dev/null
+++ b/fastlane/metadata/android/zh-CN/changelogs/40104120.txt
@@ -0,0 +1,2 @@
+此版本的主要变化:允许用户显示为离线并为音频附件添加音频播放器
+完整更改日志:https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/zh-CN/changelogs/40104130.txt b/fastlane/metadata/android/zh-CN/changelogs/40104130.txt
new file mode 100644
index 0000000000..c0b39f3f92
--- /dev/null
+++ b/fastlane/metadata/android/zh-CN/changelogs/40104130.txt
@@ -0,0 +1,2 @@
+此版本的主要变化:允许用户显示为离线并为音频附件添加音频播放器
+完整更改日志:https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/zh-CN/changelogs/40104140.txt b/fastlane/metadata/android/zh-CN/changelogs/40104140.txt
new file mode 100644
index 0000000000..c9fa249346
--- /dev/null
+++ b/fastlane/metadata/android/zh-CN/changelogs/40104140.txt
@@ -0,0 +1,2 @@
+此版本的主要变化:改进忽略用户的管理。多个bug修复及稳定性改进。
+完整更改日志:https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/zh-CN/changelogs/40104160.txt b/fastlane/metadata/android/zh-CN/changelogs/40104160.txt
new file mode 100644
index 0000000000..ef4a94f819
--- /dev/null
+++ b/fastlane/metadata/android/zh-CN/changelogs/40104160.txt
@@ -0,0 +1,2 @@
+此版本的主要变化:更好的加密消息管理。多个bug修复及稳定性改进。
+完整更改日志:https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/zh-CN/changelogs/40104180.txt b/fastlane/metadata/android/zh-CN/changelogs/40104180.txt
new file mode 100644
index 0000000000..b2c236dc31
--- /dev/null
+++ b/fastlane/metadata/android/zh-CN/changelogs/40104180.txt
@@ -0,0 +1,2 @@
+此版本的主要变化:多个bug修复及稳定性改进。
+完整更改日志:https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/zh-CN/changelogs/40104190.txt b/fastlane/metadata/android/zh-CN/changelogs/40104190.txt
new file mode 100644
index 0000000000..b2c236dc31
--- /dev/null
+++ b/fastlane/metadata/android/zh-CN/changelogs/40104190.txt
@@ -0,0 +1,2 @@
+此版本的主要变化:多个bug修复及稳定性改进。
+完整更改日志:https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/zh-CN/changelogs/40104200.txt b/fastlane/metadata/android/zh-CN/changelogs/40104200.txt
new file mode 100644
index 0000000000..9dd588cfed
--- /dev/null
+++ b/fastlane/metadata/android/zh-CN/changelogs/40104200.txt
@@ -0,0 +1,2 @@
+此版本的主要变化:Various bug fixes and stability improvements.
+完整更新日志:https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/zh-CN/changelogs/40104220.txt b/fastlane/metadata/android/zh-CN/changelogs/40104220.txt
new file mode 100644
index 0000000000..b2c236dc31
--- /dev/null
+++ b/fastlane/metadata/android/zh-CN/changelogs/40104220.txt
@@ -0,0 +1,2 @@
+此版本的主要变化:多个bug修复及稳定性改进。
+完整更改日志:https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/zh-CN/changelogs/40104230.txt b/fastlane/metadata/android/zh-CN/changelogs/40104230.txt
new file mode 100644
index 0000000000..bc5705d3e8
--- /dev/null
+++ b/fastlane/metadata/android/zh-CN/changelogs/40104230.txt
@@ -0,0 +1,2 @@
+此版本的主要变化:各种bug修复和稳定性改进。
+完整更改日志:https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/zh-CN/changelogs/40104240.txt b/fastlane/metadata/android/zh-CN/changelogs/40104240.txt
new file mode 100644
index 0000000000..bc5705d3e8
--- /dev/null
+++ b/fastlane/metadata/android/zh-CN/changelogs/40104240.txt
@@ -0,0 +1,2 @@
+此版本的主要变化:各种bug修复和稳定性改进。
+完整更改日志:https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/zh-CN/changelogs/40104250.txt b/fastlane/metadata/android/zh-CN/changelogs/40104250.txt
new file mode 100644
index 0000000000..1e7bec47dd
--- /dev/null
+++ b/fastlane/metadata/android/zh-CN/changelogs/40104250.txt
@@ -0,0 +1,2 @@
+此版本的主要变化:各种bug修复和稳定性改进。
+完整的更改日志:https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/zh-CN/changelogs/40104260.txt b/fastlane/metadata/android/zh-CN/changelogs/40104260.txt
new file mode 100644
index 0000000000..ce1efba74b
--- /dev/null
+++ b/fastlane/metadata/android/zh-CN/changelogs/40104260.txt
@@ -0,0 +1,2 @@
+此版本的主要变化:使用UnifiedPush,允许用户在没有FCM的情况下拥有推送。
+完整更新日志:https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/zh-CN/changelogs/40104270.txt b/fastlane/metadata/android/zh-CN/changelogs/40104270.txt
new file mode 100644
index 0000000000..5a3edcf1a8
--- /dev/null
+++ b/fastlane/metadata/android/zh-CN/changelogs/40104270.txt
@@ -0,0 +1,2 @@
+此版本的主要变更:多个bug修复和稳定性改善。
+完整的变更日志:https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/zh-CN/changelogs/40104280.txt b/fastlane/metadata/android/zh-CN/changelogs/40104280.txt
new file mode 100644
index 0000000000..5a3edcf1a8
--- /dev/null
+++ b/fastlane/metadata/android/zh-CN/changelogs/40104280.txt
@@ -0,0 +1,2 @@
+此版本的主要变更:多个bug修复和稳定性改善。
+完整的变更日志:https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/zh-CN/full_description.txt b/fastlane/metadata/android/zh-CN/full_description.txt
index 3dae8deb67..9b60098c34 100644
--- a/fastlane/metadata/android/zh-CN/full_description.txt
+++ b/fastlane/metadata/android/zh-CN/full_description.txt
@@ -22,9 +22,9 @@ Element 通过与其他商业协作工具,如 Slack 等应用整合,让你
你可以决定将你的资料与信息储存在何处。没有信息泄露或被第三方爬取的风险。
Element 透过不同的方式让你掌控一切:
-1. 在 Matrix 开发者架设的 matrix.org 公开服务器上取得免费帐号,或是从数千个由志愿者架设的公开服务器中选择
-2. 在你自己的 IT 基础架构上的服务器自行托管你的帐号
-3. 只要订阅 Element Matrix Services 托管平台就可以在自定义的服务器上注册帐号
+1. 在 Matrix 开发者架设的 matrix.org 公开服务器上取得免费账户,或是从数千个由志愿者架设的公开服务器中选择
+2. 在你自己的 IT 基础架构上的服务器自行托管你的账户
+3. 只要订阅 Element Matrix Services 托管平台就可以在自定义的服务器上注册账户
开放信息传递与协作
你可以与 Matrix 网络上的任何人聊天,不论他们是使用 Element、其他 Matrix 应用或其他通讯应用。
@@ -33,7 +33,7 @@ Element 透过不同的方式让你掌控一切:
真正的端到端加密(仅有那些在对话中的可以解密讯息)以及交叉签章装置验证。
完整的通讯与整合
-信息传递、语音与视频通话、文件分享、画面分享与超多的整合、机器人与挂件。建构聊天室、社群、保持联络并完成工作。
+信息传递、语音与视频通话、文件分享、画面分享与超多的整合、机器人与挂件。建构房间、社群、保持联络并完成工作。
从上次离开的地方开始
无论你身在何处,都可以透过在你所有设备与网页 https://app.element.io 间完全同步的信息历史保持联络
diff --git a/fastlane/metadata/android/zh-TW/changelogs/40104160.txt b/fastlane/metadata/android/zh-TW/changelogs/40104160.txt
new file mode 100644
index 0000000000..0e64d36868
--- /dev/null
+++ b/fastlane/metadata/android/zh-TW/changelogs/40104160.txt
@@ -0,0 +1,2 @@
+此版本中的主要變動:對於被加密的訊息有更好的管理方式。多個臭蟲修復與穩定性改善。
+完整的變更紀錄:https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/zh-TW/changelogs/40104180.txt b/fastlane/metadata/android/zh-TW/changelogs/40104180.txt
new file mode 100644
index 0000000000..4bcca9a0b8
--- /dev/null
+++ b/fastlane/metadata/android/zh-TW/changelogs/40104180.txt
@@ -0,0 +1,2 @@
+此版本中的主要變動:多個臭蟲修復與穩定性改善。
+完整的變更紀錄:https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/zh-TW/changelogs/40104190.txt b/fastlane/metadata/android/zh-TW/changelogs/40104190.txt
new file mode 100644
index 0000000000..4bcca9a0b8
--- /dev/null
+++ b/fastlane/metadata/android/zh-TW/changelogs/40104190.txt
@@ -0,0 +1,2 @@
+此版本中的主要變動:多個臭蟲修復與穩定性改善。
+完整的變更紀錄:https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/zh-TW/changelogs/40104200.txt b/fastlane/metadata/android/zh-TW/changelogs/40104200.txt
new file mode 100644
index 0000000000..4bcca9a0b8
--- /dev/null
+++ b/fastlane/metadata/android/zh-TW/changelogs/40104200.txt
@@ -0,0 +1,2 @@
+此版本中的主要變動:多個臭蟲修復與穩定性改善。
+完整的變更紀錄:https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/zh-TW/changelogs/40104220.txt b/fastlane/metadata/android/zh-TW/changelogs/40104220.txt
new file mode 100644
index 0000000000..4bcca9a0b8
--- /dev/null
+++ b/fastlane/metadata/android/zh-TW/changelogs/40104220.txt
@@ -0,0 +1,2 @@
+此版本中的主要變動:多個臭蟲修復與穩定性改善。
+完整的變更紀錄:https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/zh-TW/changelogs/40104230.txt b/fastlane/metadata/android/zh-TW/changelogs/40104230.txt
new file mode 100644
index 0000000000..4bcca9a0b8
--- /dev/null
+++ b/fastlane/metadata/android/zh-TW/changelogs/40104230.txt
@@ -0,0 +1,2 @@
+此版本中的主要變動:多個臭蟲修復與穩定性改善。
+完整的變更紀錄:https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/zh-TW/changelogs/40104240.txt b/fastlane/metadata/android/zh-TW/changelogs/40104240.txt
new file mode 100644
index 0000000000..4bcca9a0b8
--- /dev/null
+++ b/fastlane/metadata/android/zh-TW/changelogs/40104240.txt
@@ -0,0 +1,2 @@
+此版本中的主要變動:多個臭蟲修復與穩定性改善。
+完整的變更紀錄:https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/zh-TW/changelogs/40104250.txt b/fastlane/metadata/android/zh-TW/changelogs/40104250.txt
new file mode 100644
index 0000000000..4bcca9a0b8
--- /dev/null
+++ b/fastlane/metadata/android/zh-TW/changelogs/40104250.txt
@@ -0,0 +1,2 @@
+此版本中的主要變動:多個臭蟲修復與穩定性改善。
+完整的變更紀錄:https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/zh-TW/changelogs/40104260.txt b/fastlane/metadata/android/zh-TW/changelogs/40104260.txt
new file mode 100644
index 0000000000..7569b4f491
--- /dev/null
+++ b/fastlane/metadata/android/zh-TW/changelogs/40104260.txt
@@ -0,0 +1,2 @@
+此版本中的主要變動:使用 UnifiedPush 並允許使用者在沒有 FCM 的情況下推送。
+完整的變更紀錄:https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/zh-TW/changelogs/40104270.txt b/fastlane/metadata/android/zh-TW/changelogs/40104270.txt
new file mode 100644
index 0000000000..4bcca9a0b8
--- /dev/null
+++ b/fastlane/metadata/android/zh-TW/changelogs/40104270.txt
@@ -0,0 +1,2 @@
+此版本中的主要變動:多個臭蟲修復與穩定性改善。
+完整的變更紀錄:https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/zh-TW/changelogs/40104280.txt b/fastlane/metadata/android/zh-TW/changelogs/40104280.txt
new file mode 100644
index 0000000000..4bcca9a0b8
--- /dev/null
+++ b/fastlane/metadata/android/zh-TW/changelogs/40104280.txt
@@ -0,0 +1,2 @@
+此版本中的主要變動:多個臭蟲修復與穩定性改善。
+完整的變更紀錄:https://github.com/vector-im/element-android/releases
diff --git a/gradle.properties b/gradle.properties
index 6de52be607..2af9214ed5 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -32,3 +32,8 @@ signing.element.storePath=pathTo.keystore
signing.element.storePassword=Secret
signing.element.keyId=Secret
signing.element.keyPassword=Secret
+
+# Dummy values for signing secrets / nightly
+signing.element.nightly.storePassword=Secret
+signing.element.nightly.keyId=Secret
+signing.element.nightly.keyPassword=Secret
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index 41d9927a4d..249e5832f0 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index e1e0c8dc42..f7189a776c 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionSha256Sum=e6d864e3b5bc05cc62041842b306383fc1fefcec359e70cebb1d470a6094ca82
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip
+distributionSha256Sum=db9c8211ed63f61f60292c69e80d89196f9eb36665e369e7f00ac4cc841c2219
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
index 1b6c787337..a69d9cb6c2 100755
--- a/gradlew
+++ b/gradlew
@@ -205,6 +205,12 @@ set -- \
org.gradle.wrapper.GradleWrapperMain \
"$@"
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+ die "xargs is not available"
+fi
+
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
diff --git a/gradlew.bat b/gradlew.bat
index ac1b06f938..53a6b238d4 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -14,7 +14,7 @@
@rem limitations under the License.
@rem
-@if "%DEBUG%" == "" @echo off
+@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@@ -25,7 +25,7 @@
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
+if "%DIRNAME%"=="" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto execute
+if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -75,13 +75,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
:end
@rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
+if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
-if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-exit /b 1
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
diff --git a/library/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AttachmentViewerActivity.kt b/library/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AttachmentViewerActivity.kt
index 21af114c26..764cf8419a 100644
--- a/library/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AttachmentViewerActivity.kt
+++ b/library/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AttachmentViewerActivity.kt
@@ -271,7 +271,7 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi
directionDetector.handleTouchEvent(event)
return when (swipeDirection) {
- SwipeDirection.Up, SwipeDirection.Down -> {
+ SwipeDirection.Up, SwipeDirection.Down -> {
if (isSwipeToDismissAllowed && !wasScaled && isImagePagerIdle) {
swipeDismissHandler.onTouch(views.rootContainer, event)
} else true
@@ -279,7 +279,7 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi
SwipeDirection.Left, SwipeDirection.Right -> {
views.attachmentPager.dispatchTouchEvent(event)
}
- else -> true
+ else -> true
}
}
diff --git a/library/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AttachmentsAdapter.kt b/library/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AttachmentsAdapter.kt
index 4805a1186b..77ddb27c63 100644
--- a/library/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AttachmentsAdapter.kt
+++ b/library/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AttachmentsAdapter.kt
@@ -42,18 +42,18 @@ class AttachmentsAdapter : RecyclerView.Adapter() {
val inflater = LayoutInflater.from(parent.context)
val itemView = inflater.inflate(viewType, parent, false)
return when (viewType) {
- R.layout.item_image_attachment -> ZoomableImageViewHolder(itemView)
+ R.layout.item_image_attachment -> ZoomableImageViewHolder(itemView)
R.layout.item_animated_image_attachment -> AnimatedImageViewHolder(itemView)
- R.layout.item_video_attachment -> VideoViewHolder(itemView)
- else -> UnsupportedViewHolder(itemView)
+ R.layout.item_video_attachment -> VideoViewHolder(itemView)
+ else -> UnsupportedViewHolder(itemView)
}
}
override fun getItemViewType(position: Int): Int {
val info = attachmentSourceProvider!!.getAttachmentInfoAt(position)
return when (info) {
- is AttachmentInfo.Image -> R.layout.item_image_attachment
- is AttachmentInfo.Video -> R.layout.item_video_attachment
+ is AttachmentInfo.Image -> R.layout.item_image_attachment
+ is AttachmentInfo.Video -> R.layout.item_video_attachment
is AttachmentInfo.AnimatedImage -> R.layout.item_animated_image_attachment
// is AttachmentInfo.Audio -> TODO()
// is AttachmentInfo.File -> TODO()
@@ -68,13 +68,13 @@ class AttachmentsAdapter : RecyclerView.Adapter() {
attachmentSourceProvider?.getAttachmentInfoAt(position)?.let {
holder.bind(it)
when (it) {
- is AttachmentInfo.Image -> {
+ is AttachmentInfo.Image -> {
attachmentSourceProvider?.loadImage((holder as ZoomableImageViewHolder).target, it)
}
is AttachmentInfo.AnimatedImage -> {
attachmentSourceProvider?.loadImage((holder as AnimatedImageViewHolder).target, it)
}
- is AttachmentInfo.Video -> {
+ is AttachmentInfo.Video -> {
attachmentSourceProvider?.loadVideo((holder as VideoViewHolder).target, it)
}
// else -> {
diff --git a/library/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/SwipeDirection.kt b/library/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/SwipeDirection.kt
index 7948f37ae8..7816a5a2cc 100644
--- a/library/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/SwipeDirection.kt
+++ b/library/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/SwipeDirection.kt
@@ -27,12 +27,12 @@ sealed class SwipeDirection {
companion object {
fun fromAngle(angle: Double): SwipeDirection {
return when (angle) {
- in 0.0..45.0 -> Right
- in 45.0..135.0 -> Up
+ in 0.0..45.0 -> Right
+ in 45.0..135.0 -> Up
in 135.0..225.0 -> Left
in 225.0..315.0 -> Down
in 315.0..360.0 -> Right
- else -> NotDetected
+ else -> NotDetected
}
}
}
diff --git a/library/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/SwipeDirectionDetector.kt b/library/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/SwipeDirectionDetector.kt
index 6575248b2d..7b72637c06 100644
--- a/library/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/SwipeDirectionDetector.kt
+++ b/library/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/SwipeDirectionDetector.kt
@@ -33,7 +33,7 @@ class SwipeDirectionDetector(
fun handleTouchEvent(event: MotionEvent) {
when (event.action) {
- MotionEvent.ACTION_DOWN -> {
+ MotionEvent.ACTION_DOWN -> {
startX = event.x
startY = event.y
}
@@ -45,7 +45,7 @@ class SwipeDirectionDetector(
startX = startY
isDetected = false
}
- MotionEvent.ACTION_MOVE -> if (!isDetected && getEventDistance(event) > touchSlop) {
+ MotionEvent.ACTION_MOVE -> if (!isDetected && getEventDistance(event) > touchSlop) {
isDetected = true
onDirectionDetected(getDirection(startX, startY, event.x, event.y))
}
diff --git a/library/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/SwipeToDismissHandler.kt b/library/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/SwipeToDismissHandler.kt
index 85d7c13398..7a83ee28d4 100644
--- a/library/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/SwipeToDismissHandler.kt
+++ b/library/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/SwipeToDismissHandler.kt
@@ -79,8 +79,8 @@ class SwipeToDismissHandler(
private fun onTrackingEnd(parentHeight: Int) {
val animateTo = when {
swipeView.translationY < -translationLimit -> -parentHeight.toFloat()
- swipeView.translationY > translationLimit -> parentHeight.toFloat()
- else -> 0f
+ swipeView.translationY > translationLimit -> parentHeight.toFloat()
+ else -> 0f
}
if (animateTo != 0f && !shouldAnimateDismiss()) {
diff --git a/library/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/VideoViewHolder.kt b/library/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/VideoViewHolder.kt
index 12213a8786..92d28d26c9 100644
--- a/library/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/VideoViewHolder.kt
+++ b/library/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/VideoViewHolder.kt
@@ -146,7 +146,7 @@ class VideoViewHolder constructor(itemView: View) :
wasPaused = true
views.videoView.pause()
}
- is AttachmentCommands.SeekTo -> {
+ is AttachmentCommands.SeekTo -> {
val duration = views.videoView.duration
if (duration > 0) {
val seekDuration = duration * (commands.percentProgress / 100f)
diff --git a/library/jsonviewer/build.gradle b/library/jsonviewer/build.gradle
index e1a3b0c9ee..ad472b0b54 100644
--- a/library/jsonviewer/build.gradle
+++ b/library/jsonviewer/build.gradle
@@ -2,7 +2,6 @@ apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-parcelize'
apply plugin: 'kotlin-kapt'
-apply plugin: 'com.jakewharton.butterknife'
buildscript {
repositories {
@@ -15,9 +14,6 @@ buildscript {
url 'https://repo1.maven.org/maven2'
}
}
- dependencies {
- classpath 'com.jakewharton:butterknife-gradle-plugin:10.2.3'
- }
}
android {
diff --git a/library/jsonviewer/src/main/java/org/billcarsonfr/jsonviewer/JSonViewerEpoxyController.kt b/library/jsonviewer/src/main/java/org/billcarsonfr/jsonviewer/JSonViewerEpoxyController.kt
index 9f8093f801..24b9f2ec26 100644
--- a/library/jsonviewer/src/main/java/org/billcarsonfr/jsonviewer/JSonViewerEpoxyController.kt
+++ b/library/jsonviewer/src/main/java/org/billcarsonfr/jsonviewer/JSonViewerEpoxyController.kt
@@ -43,7 +43,7 @@ internal class JSonViewerEpoxyController(private val context: Context) :
text(async.error.localizedMessage?.toEpoxyCharSequence())
}
}
- else -> {
+ else -> {
async.invoke()?.let {
buildRec(it, 0, "")
}
@@ -98,7 +98,7 @@ internal class JSonViewerEpoxyController(private val context: Context) :
}
}
}
- is JSonViewerArray -> {
+ is JSonViewerArray -> {
if (model.isExpanded) {
open(id, model.key, model.index, depth, false, model)
model.items.forEach {
@@ -137,7 +137,7 @@ internal class JSonViewerEpoxyController(private val context: Context) :
}
}
}
- is JSonViewerLeaf -> {
+ is JSonViewerLeaf -> {
valueItem {
id(id)
depth(depth)
@@ -172,12 +172,12 @@ internal class JSonViewerEpoxyController(private val context: Context) :
private fun valueToSpan(leaf: JSonViewerLeaf): Span {
val host = this
return when (leaf.type) {
- JSONType.STRING -> {
+ JSONType.STRING -> {
span("\"${leaf.stringRes}\"") {
textColor = host.styleProvider.stringColor
}
}
- JSONType.NUMBER -> {
+ JSONType.NUMBER -> {
span(leaf.stringRes) {
textColor = host.styleProvider.numberColor
}
@@ -187,7 +187,7 @@ internal class JSonViewerEpoxyController(private val context: Context) :
textColor = host.styleProvider.booleanColor
}
}
- JSONType.NULL -> {
+ JSONType.NULL -> {
span("null") {
textColor = host.styleProvider.booleanColor
}
diff --git a/library/jsonviewer/src/main/java/org/billcarsonfr/jsonviewer/JSonViewerModel.kt b/library/jsonviewer/src/main/java/org/billcarsonfr/jsonviewer/JSonViewerModel.kt
index 6940e79e3f..2492b5454c 100644
--- a/library/jsonviewer/src/main/java/org/billcarsonfr/jsonviewer/JSonViewerModel.kt
+++ b/library/jsonviewer/src/main/java/org/billcarsonfr/jsonviewer/JSonViewerModel.kt
@@ -82,7 +82,7 @@ internal object ModelParser {
}
parent.addChild(objectComposed)
}
- is JSONArray -> {
+ is JSONArray -> {
val objectComposed = JSonViewerArray(key, index, obj)
.apply { isExpanded = initialOpenDepth == -1 || depth <= initialOpenDepth }
objectComposed.depth = depth
@@ -91,25 +91,25 @@ internal object ModelParser {
}
parent.addChild(objectComposed)
}
- is String -> {
+ is String -> {
JSonViewerLeaf(key, index, obj, JSONType.STRING).let {
it.depth = depth
parent.addChild(it)
}
}
- is Number -> {
+ is Number -> {
JSonViewerLeaf(key, index, obj.toString(), JSONType.NUMBER).let {
it.depth = depth
parent.addChild(it)
}
}
- is Boolean -> {
+ is Boolean -> {
JSonViewerLeaf(key, index, obj.toString(), JSONType.BOOLEAN).let {
it.depth = depth
parent.addChild(it)
}
}
- else -> {
+ else -> {
if (obj == JSONObject.NULL) {
JSonViewerLeaf(key, index, "null", JSONType.NULL).let {
it.depth = depth
diff --git a/library/jsonviewer/src/main/java/org/billcarsonfr/jsonviewer/ValueItem.kt b/library/jsonviewer/src/main/java/org/billcarsonfr/jsonviewer/ValueItem.kt
index 66dfcc5dc3..590df07f4d 100644
--- a/library/jsonviewer/src/main/java/org/billcarsonfr/jsonviewer/ValueItem.kt
+++ b/library/jsonviewer/src/main/java/org/billcarsonfr/jsonviewer/ValueItem.kt
@@ -29,7 +29,7 @@ import com.airbnb.epoxy.EpoxyModelClass
import com.airbnb.epoxy.EpoxyModelWithHolder
import im.vector.lib.core.utils.epoxy.charsequence.EpoxyCharSequence
-@EpoxyModelClass(layout = R2.layout.item_jv_base_value)
+@EpoxyModelClass
internal abstract class ValueItem : EpoxyModelWithHolder() {
@EpoxyAttribute
@@ -44,6 +44,8 @@ internal abstract class ValueItem : EpoxyModelWithHolder() {
@EpoxyAttribute(EpoxyAttribute.Option.DoNotHash)
var itemClickListener: View.OnClickListener? = null
+ override fun getDefaultLayout() = R.layout.item_jv_base_value
+
override fun bind(holder: Holder) {
super.bind(holder)
holder.textView.text = text?.charSequence
diff --git a/library/multipicker/src/main/java/im/vector/lib/multipicker/FilePicker.kt b/library/multipicker/src/main/java/im/vector/lib/multipicker/FilePicker.kt
index 13ef5aa637..928fdf894c 100644
--- a/library/multipicker/src/main/java/im/vector/lib/multipicker/FilePicker.kt
+++ b/library/multipicker/src/main/java/im/vector/lib/multipicker/FilePicker.kt
@@ -48,7 +48,7 @@ class FilePicker : Picker() {
type.isMimeTypeVideo() -> selectedUri.toMultiPickerVideoType(context)
type.isMimeTypeImage() -> selectedUri.toMultiPickerImageType(context)
type.isMimeTypeAudio() -> selectedUri.toMultiPickerAudioType(context)
- else -> {
+ else -> {
// Other files
context.contentResolver.query(selectedUri, null, null, null, null)
?.use { cursor ->
diff --git a/library/multipicker/src/main/java/im/vector/lib/multipicker/MediaPicker.kt b/library/multipicker/src/main/java/im/vector/lib/multipicker/MediaPicker.kt
index db74dbf9ff..82d0e358df 100644
--- a/library/multipicker/src/main/java/im/vector/lib/multipicker/MediaPicker.kt
+++ b/library/multipicker/src/main/java/im/vector/lib/multipicker/MediaPicker.kt
@@ -49,7 +49,7 @@ class MediaPicker : Picker() {
return Intent(Intent.ACTION_GET_CONTENT).apply {
addCategory(Intent.CATEGORY_OPENABLE)
putExtra(Intent.EXTRA_ALLOW_MULTIPLE, !single)
- type = "video/*, image/*"
+ type = "*/*"
val mimeTypes = arrayOf("image/*", "video/*")
putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes)
}
diff --git a/library/multipicker/src/main/java/im/vector/lib/multipicker/MultiPicker.kt b/library/multipicker/src/main/java/im/vector/lib/multipicker/MultiPicker.kt
index e7883c9e53..9377345886 100644
--- a/library/multipicker/src/main/java/im/vector/lib/multipicker/MultiPicker.kt
+++ b/library/multipicker/src/main/java/im/vector/lib/multipicker/MultiPicker.kt
@@ -31,15 +31,15 @@ class MultiPicker private constructor() {
@Suppress("UNCHECKED_CAST")
fun get(type: MultiPicker): T {
return when (type) {
- IMAGE -> ImagePicker() as T
- VIDEO -> VideoPicker() as T
- MEDIA -> MediaPicker() as T
- FILE -> FilePicker() as T
- AUDIO -> AudioPicker() as T
- CONTACT -> ContactPicker() as T
- CAMERA -> CameraPicker() as T
+ IMAGE -> ImagePicker() as T
+ VIDEO -> VideoPicker() as T
+ MEDIA -> MediaPicker() as T
+ FILE -> FilePicker() as T
+ AUDIO -> AudioPicker() as T
+ CONTACT -> ContactPicker() as T
+ CAMERA -> CameraPicker() as T
CAMERA_VIDEO -> CameraVideoPicker() as T
- else -> throw IllegalArgumentException("Unsupported type $type")
+ else -> throw IllegalArgumentException("Unsupported type $type")
}
}
}
diff --git a/library/ui-styles/build.gradle b/library/ui-styles/build.gradle
index 31cfdd24c7..c85f26dbc4 100644
--- a/library/ui-styles/build.gradle
+++ b/library/ui-styles/build.gradle
@@ -53,11 +53,10 @@ android {
dependencies {
implementation libs.androidx.appCompat
+ implementation libs.androidx.fragmentKtx
implementation libs.google.material
// Pref theme
implementation libs.androidx.preferenceKtx
- // PFLockScreen attrs
- implementation 'com.github.vector-im:PFLockScreen-Android:1.0.0-beta12'
// dialpad dimen
implementation 'im.dlg:android-dialer:1.2.5'
}
diff --git a/library/ui-styles/src/debug/java/im/vector/lib/ui/styles/debug/DebugMaterialThemeActivity.kt b/library/ui-styles/src/debug/java/im/vector/lib/ui/styles/debug/DebugMaterialThemeActivity.kt
index 553d495e22..412d6fdc1c 100644
--- a/library/ui-styles/src/debug/java/im/vector/lib/ui/styles/debug/DebugMaterialThemeActivity.kt
+++ b/library/ui-styles/src/debug/java/im/vector/lib/ui/styles/debug/DebugMaterialThemeActivity.kt
@@ -18,8 +18,12 @@ package im.vector.lib.ui.styles.debug
import android.os.Bundle
import android.view.Menu
+import android.view.MenuInflater
+import android.view.MenuItem
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
+import androidx.core.view.MenuProvider
+import androidx.lifecycle.Lifecycle
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.snackbar.Snackbar
import im.vector.lib.ui.styles.R
@@ -31,6 +35,7 @@ abstract class DebugMaterialThemeActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
+ setupMenu()
val views = ActivityDebugMaterialThemeBinding.inflate(layoutInflater)
setContentView(views.root)
@@ -72,6 +77,27 @@ abstract class DebugMaterialThemeActivity : AppCompatActivity() {
}
}
+ private fun setupMenu() {
+ addMenuProvider(
+ object : MenuProvider {
+ override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
+ menuInflater.inflate(R.menu.menu_debug, menu)
+ }
+
+ override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
+ Toast.makeText(
+ this@DebugMaterialThemeActivity,
+ "Menu ${menuItem.title} clicked!",
+ Toast.LENGTH_SHORT
+ ).show()
+ return true
+ }
+ },
+ this,
+ Lifecycle.State.RESUMED
+ )
+ }
+
private fun showTestDialog(theme: Int) {
MaterialAlertDialogBuilder(this, theme)
.setTitle("Dialog title")
@@ -82,9 +108,4 @@ abstract class DebugMaterialThemeActivity : AppCompatActivity() {
.setNeutralButton("Neutral", null)
.show()
}
-
- override fun onCreateOptionsMenu(menu: Menu): Boolean {
- menuInflater.inflate(R.menu.menu_debug, menu)
- return true
- }
}
diff --git a/library/ui-styles/src/main/res/color/radio_button_tint_selector.xml b/library/ui-styles/src/main/res/color/radio_button_tint_selector.xml
new file mode 100644
index 0000000000..527738b306
--- /dev/null
+++ b/library/ui-styles/src/main/res/color/radio_button_tint_selector.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/library/ui-styles/src/main/res/color/vector_content_primary_tint_selector.xml b/library/ui-styles/src/main/res/color/vector_content_primary_tint_selector.xml
new file mode 100644
index 0000000000..26b911391f
--- /dev/null
+++ b/library/ui-styles/src/main/res/color/vector_content_primary_tint_selector.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/library/ui-styles/src/main/res/drawable/bg_waiting_for_email_verification.xml b/library/ui-styles/src/main/res/drawable/bg_gradient_ftue_breaker.xml
similarity index 100%
rename from library/ui-styles/src/main/res/drawable/bg_waiting_for_email_verification.xml
rename to library/ui-styles/src/main/res/drawable/bg_gradient_ftue_breaker.xml
diff --git a/library/ui-styles/src/main/res/drawable/ic_home_search.xml b/library/ui-styles/src/main/res/drawable/ic_home_search.xml
new file mode 100644
index 0000000000..5cb88ba1e4
--- /dev/null
+++ b/library/ui-styles/src/main/res/drawable/ic_home_search.xml
@@ -0,0 +1,4 @@
+
+
+
diff --git a/library/ui-styles/src/main/res/drawable/lockscreen_background.xml b/library/ui-styles/src/main/res/drawable/lockscreen_background.xml
new file mode 100644
index 0000000000..5688c433f7
--- /dev/null
+++ b/library/ui-styles/src/main/res/drawable/lockscreen_background.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/library/ui-styles/src/main/res/drawable/lockscreen_circle_background.xml b/library/ui-styles/src/main/res/drawable/lockscreen_circle_background.xml
new file mode 100644
index 0000000000..87fa99063c
--- /dev/null
+++ b/library/ui-styles/src/main/res/drawable/lockscreen_circle_background.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/library/ui-styles/src/main/res/drawable/lockscreen_circle_code_empty.xml b/library/ui-styles/src/main/res/drawable/lockscreen_circle_code_empty.xml
new file mode 100644
index 0000000000..abde6087e0
--- /dev/null
+++ b/library/ui-styles/src/main/res/drawable/lockscreen_circle_code_empty.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
diff --git a/library/ui-styles/src/main/res/drawable/lockscreen_circle_code_fill.xml b/library/ui-styles/src/main/res/drawable/lockscreen_circle_code_fill.xml
new file mode 100644
index 0000000000..e3f1082324
--- /dev/null
+++ b/library/ui-styles/src/main/res/drawable/lockscreen_circle_code_fill.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
diff --git a/library/ui-styles/src/main/res/drawable/lockscreen_circle_key_selector.xml b/library/ui-styles/src/main/res/drawable/lockscreen_circle_key_selector.xml
new file mode 100644
index 0000000000..3fdebfbbe0
--- /dev/null
+++ b/library/ui-styles/src/main/res/drawable/lockscreen_circle_key_selector.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/library/ui-styles/src/main/res/drawable/lockscreen_code_selector.xml b/library/ui-styles/src/main/res/drawable/lockscreen_code_selector.xml
new file mode 100644
index 0000000000..5de4957a3b
--- /dev/null
+++ b/library/ui-styles/src/main/res/drawable/lockscreen_code_selector.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
diff --git a/library/ui-styles/src/main/res/drawable/lockscreen_delete.xml b/library/ui-styles/src/main/res/drawable/lockscreen_delete.xml
new file mode 100644
index 0000000000..e1d70e8f41
--- /dev/null
+++ b/library/ui-styles/src/main/res/drawable/lockscreen_delete.xml
@@ -0,0 +1,7 @@
+
+
+
+
diff --git a/library/ui-styles/src/main/res/drawable/lockscreen_fingerprint.xml b/library/ui-styles/src/main/res/drawable/lockscreen_fingerprint.xml
new file mode 100644
index 0000000000..7f0abe850a
--- /dev/null
+++ b/library/ui-styles/src/main/res/drawable/lockscreen_fingerprint.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/library/ui-styles/src/main/res/drawable/lockscreen_side_button_background.xml b/library/ui-styles/src/main/res/drawable/lockscreen_side_button_background.xml
new file mode 100644
index 0000000000..b205b2d91c
--- /dev/null
+++ b/library/ui-styles/src/main/res/drawable/lockscreen_side_button_background.xml
@@ -0,0 +1,29 @@
+
+
+
+ -
+
+
+
+
+
+
+
+ -
+
+
-
+
+
+
+ -
+
+
+
+ -
+
+
+
+
+
diff --git a/library/ui-styles/src/main/res/drawable/lockscreen_touch_selector.xml b/library/ui-styles/src/main/res/drawable/lockscreen_touch_selector.xml
new file mode 100644
index 0000000000..141f2ac698
--- /dev/null
+++ b/library/ui-styles/src/main/res/drawable/lockscreen_touch_selector.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/library/ui-styles/src/main/res/values-land/lockscreen_default_dimen.xml b/library/ui-styles/src/main/res/values-land/lockscreen_default_dimen.xml
new file mode 100644
index 0000000000..2ae3ca0689
--- /dev/null
+++ b/library/ui-styles/src/main/res/values-land/lockscreen_default_dimen.xml
@@ -0,0 +1,5 @@
+
+
+ 60dp
+ 15dp
+
diff --git a/library/ui-styles/src/main/res/values/dimens.xml b/library/ui-styles/src/main/res/values/dimens.xml
index 70d051b457..53f1044a12 100644
--- a/library/ui-styles/src/main/res/values/dimens.xml
+++ b/library/ui-styles/src/main/res/values/dimens.xml
@@ -71,4 +71,7 @@
8dp
12dp
22dp
+
+
+ 112dp
diff --git a/library/ui-styles/src/main/res/values/dimens_font.xml b/library/ui-styles/src/main/res/values/dimens_font.xml
index 1b5a826acb..ad8f012a16 100644
--- a/library/ui-styles/src/main/res/values/dimens_font.xml
+++ b/library/ui-styles/src/main/res/values/dimens_font.xml
@@ -7,7 +7,8 @@
14sp
12sp
10sp
+ 8sp
14sp
-
\ No newline at end of file
+
diff --git a/library/ui-styles/src/main/res/values/lockscreen_attr.xml b/library/ui-styles/src/main/res/values/lockscreen_attr.xml
new file mode 100644
index 0000000000..64e77d3c4e
--- /dev/null
+++ b/library/ui-styles/src/main/res/values/lockscreen_attr.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/library/ui-styles/src/main/res/values/lockscreen_default_colors.xml b/library/ui-styles/src/main/res/values/lockscreen_default_colors.xml
new file mode 100644
index 0000000000..eb9115d636
--- /dev/null
+++ b/library/ui-styles/src/main/res/values/lockscreen_default_colors.xml
@@ -0,0 +1,8 @@
+
+
+ #ffffff
+ #66ffffff
+ #42000000
+ #f4511e
+ #009688
+
diff --git a/library/ui-styles/src/main/res/values/lockscreen_default_dimens.xml b/library/ui-styles/src/main/res/values/lockscreen_default_dimens.xml
new file mode 100644
index 0000000000..7d30f179a6
--- /dev/null
+++ b/library/ui-styles/src/main/res/values/lockscreen_default_dimens.xml
@@ -0,0 +1,7 @@
+
+
+ 70dp
+ 25dp
+ 10dp
+ 5dp
+
diff --git a/library/ui-styles/src/main/res/values/lockscreen_default_strings.xml b/library/ui-styles/src/main/res/values/lockscreen_default_strings.xml
new file mode 100644
index 0000000000..f0d7a75851
--- /dev/null
+++ b/library/ui-styles/src/main/res/values/lockscreen_default_strings.xml
@@ -0,0 +1,17 @@
+
+ Cancel
+ Use pin
+ Sign in
+ Next
+ Forgot?
+ Input pin code or use biometric authentication
+ Fingerprint not recognized. Try again
+ Fingerprint recognized
+
+ Confirm fingerprint to continue
+ Touch sensor
+ Fingerprint icon
+ Confirm PIN
+ Logo
+
+
diff --git a/library/ui-styles/src/main/res/values/lockscreen_default_styles.xml b/library/ui-styles/src/main/res/values/lockscreen_default_styles.xml
new file mode 100644
index 0000000000..dba92df0bb
--- /dev/null
+++ b/library/ui-styles/src/main/res/values/lockscreen_default_styles.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/library/ui-styles/src/main/res/values/stylable_devices_list_header_view.xml b/library/ui-styles/src/main/res/values/stylable_devices_list_header_view.xml
new file mode 100644
index 0000000000..f0807f89c6
--- /dev/null
+++ b/library/ui-styles/src/main/res/values/stylable_devices_list_header_view.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/library/ui-styles/src/main/res/values/stylable_live_location_ended_banner_view.xml b/library/ui-styles/src/main/res/values/stylable_live_location_ended_banner_view.xml
new file mode 100644
index 0000000000..30ac6229c5
--- /dev/null
+++ b/library/ui-styles/src/main/res/values/stylable_live_location_ended_banner_view.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/library/ui-styles/src/main/res/values/stylable_map_loading_error_view.xml b/library/ui-styles/src/main/res/values/stylable_map_loading_error_view.xml
new file mode 100644
index 0000000000..911167e52a
--- /dev/null
+++ b/library/ui-styles/src/main/res/values/stylable_map_loading_error_view.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/library/ui-styles/src/main/res/values/styles_bottom_sheet.xml b/library/ui-styles/src/main/res/values/styles_bottom_sheet.xml
index 9f17342ede..f6c30040d9 100644
--- a/library/ui-styles/src/main/res/values/styles_bottom_sheet.xml
+++ b/library/ui-styles/src/main/res/values/styles_bottom_sheet.xml
@@ -4,10 +4,13 @@
-
\ No newline at end of file
+
diff --git a/library/ui-styles/src/main/res/values/styles_buttons.xml b/library/ui-styles/src/main/res/values/styles_buttons.xml
index 004aca5aaa..702f427cc0 100644
--- a/library/ui-styles/src/main/res/values/styles_buttons.xml
+++ b/library/ui-styles/src/main/res/values/styles_buttons.xml
@@ -65,4 +65,8 @@
- ?colorOnPrimary
-
\ No newline at end of file
+
+
+
diff --git a/library/ui-styles/src/main/res/values/styles_devices_management.xml b/library/ui-styles/src/main/res/values/styles_devices_management.xml
new file mode 100644
index 0000000000..2a63c2ed36
--- /dev/null
+++ b/library/ui-styles/src/main/res/values/styles_devices_management.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
diff --git a/library/ui-styles/src/main/res/values/styles_location.xml b/library/ui-styles/src/main/res/values/styles_location.xml
index 9d9fc862f6..ee893046ba 100644
--- a/library/ui-styles/src/main/res/values/styles_location.xml
+++ b/library/ui-styles/src/main/res/values/styles_location.xml
@@ -1,21 +1,27 @@
-
-
+
+
diff --git a/library/ui-styles/src/main/res/values/styles_pin_code.xml b/library/ui-styles/src/main/res/values/styles_pin_code.xml
index cb22863694..8459778e29 100644
--- a/library/ui-styles/src/main/res/values/styles_pin_code.xml
+++ b/library/ui-styles/src/main/res/values/styles_pin_code.xml
@@ -22,13 +22,13 @@
diff --git a/library/ui-styles/src/main/res/values/styles_tablayout.xml b/library/ui-styles/src/main/res/values/styles_tablayout.xml
new file mode 100644
index 0000000000..ab26972995
--- /dev/null
+++ b/library/ui-styles/src/main/res/values/styles_tablayout.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/library/ui-styles/src/main/res/values/styles_text_view.xml b/library/ui-styles/src/main/res/values/styles_text_view.xml
index 77e32da345..0dcaf30f48 100644
--- a/library/ui-styles/src/main/res/values/styles_text_view.xml
+++ b/library/ui-styles/src/main/res/values/styles_text_view.xml
@@ -48,4 +48,9 @@
- 16sp
-
\ No newline at end of file
+
+
+
diff --git a/library/ui-styles/src/main/res/values/styles_toolbar.xml b/library/ui-styles/src/main/res/values/styles_toolbar.xml
index 505419c6fe..893de92aae 100644
--- a/library/ui-styles/src/main/res/values/styles_toolbar.xml
+++ b/library/ui-styles/src/main/res/values/styles_toolbar.xml
@@ -39,4 +39,14 @@
- 12sp
-
\ No newline at end of file
+
+
+
+
+
+
+
diff --git a/library/ui-styles/src/main/res/values/text_appearances.xml b/library/ui-styles/src/main/res/values/text_appearances.xml
index 8e30dd00d6..570d26fdfd 100644
--- a/library/ui-styles/src/main/res/values/text_appearances.xml
+++ b/library/ui-styles/src/main/res/values/text_appearances.xml
@@ -32,6 +32,15 @@
- ?vctr_content_primary
+
+
+
+
diff --git a/library/ui-styles/src/main/res/values/theme_common.xml b/library/ui-styles/src/main/res/values/theme_common.xml
index 2e9c2c5123..107534fe1a 100644
--- a/library/ui-styles/src/main/res/values/theme_common.xml
+++ b/library/ui-styles/src/main/res/values/theme_common.xml
@@ -25,4 +25,4 @@
- false
-
\ No newline at end of file
+
diff --git a/library/ui-styles/src/main/res/values/theme_dark.xml b/library/ui-styles/src/main/res/values/theme_dark.xml
index 733f7e8eb5..9f4e5c1e28 100644
--- a/library/ui-styles/src/main/res/values/theme_dark.xml
+++ b/library/ui-styles/src/main/res/values/theme_dark.xml
@@ -111,14 +111,14 @@
- @style/PreferenceThemeOverlay.v14.Material
- - @style/PinCodeScreenStyle
- - @style/PinCodeKeyButtonStyle
- - @style/PinCodeTitleStyle
- - @style/PinCodeHintStyle
- - @style/PinCodeDotsViewStyle
- - @style/PinCodeDeleteButtonStyle
- - @style/PinCodeFingerprintButtonStyle
- - @style/PinCodeNextButtonStyle
+ - @style/PinCodeScreenStyle
+ - @style/PinCodeKeyButtonStyle
+ - @style/PinCodeTitleStyle
+ - @style/PinCodeHintStyle
+ - @style/PinCodeDotsViewStyle
+ - @style/PinCodeDeleteButtonStyle
+ - @style/PinCodeFingerprintButtonStyle
+ - @style/PinCodeNextButtonStyle
- @color/android_status_bar_background_dark
- @color/android_navigation_bar_background_dark
@@ -149,6 +149,9 @@
- @color/vctr_live_location_dark
+
+
+ - @dimen/collapsing_toolbar_layout_medium_size
diff --git a/library/ui-styles/src/main/res/values/theme_light.xml b/library/ui-styles/src/main/res/values/theme_light.xml
index 77996c8ce5..c8182abecc 100644
--- a/library/ui-styles/src/main/res/values/theme_light.xml
+++ b/library/ui-styles/src/main/res/values/theme_light.xml
@@ -111,14 +111,14 @@
- @style/PreferenceThemeOverlay.v14.Material
- - @style/PinCodeScreenStyle
- - @style/PinCodeKeyButtonStyle
- - @style/PinCodeTitleStyle
- - @style/PinCodeHintStyle
- - @style/PinCodeDotsViewStyle
- - @style/PinCodeDeleteButtonStyle
- - @style/PinCodeFingerprintButtonStyle
- - @style/PinCodeNextButtonStyle
+ - @style/PinCodeScreenStyle
+ - @style/PinCodeKeyButtonStyle
+ - @style/PinCodeTitleStyle
+ - @style/PinCodeHintStyle
+ - @style/PinCodeDotsViewStyle
+ - @style/PinCodeDeleteButtonStyle
+ - @style/PinCodeFingerprintButtonStyle
+ - @style/PinCodeNextButtonStyle
- @color/android_status_bar_background_dark
@@ -150,8 +150,12 @@
- @color/vctr_live_location_light
+
+
+ - @dimen/collapsing_toolbar_layout_medium_size
+
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 90546756b8..8be8e83569 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
@@ -18,7 +18,7 @@ package org.matrix.android.sdk.flow
import androidx.lifecycle.asFlow
import kotlinx.coroutines.flow.Flow
-import org.matrix.android.sdk.api.query.QueryStringValue
+import org.matrix.android.sdk.api.query.QueryStateEventValue
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
@@ -53,6 +53,13 @@ class FlowRoom(private val room: Room) {
}
}
+ fun liveAreAllMembersLoaded(): Flow {
+ return room.membershipService().areAllMembersLoadedLive().asFlow()
+ .startWith(room.coroutineDispatchers.io) {
+ room.membershipService().areAllMembersLoaded()
+ }
+ }
+
fun liveAnnotationSummary(eventId: String): Flow> {
return room.relationService().getEventAnnotationsSummaryLive(eventId).asFlow()
.startWith(room.coroutineDispatchers.io) {
@@ -67,17 +74,17 @@ class FlowRoom(private val room: Room) {
}
}
- fun liveStateEvent(eventType: String, stateKey: QueryStringValue): Flow> {
+ fun liveStateEvent(eventType: String, stateKey: QueryStateEventValue): Flow> {
return room.stateService().getStateEventLive(eventType, stateKey).asFlow()
.startWith(room.coroutineDispatchers.io) {
room.getStateEvent(eventType, stateKey).toOptional()
}
}
- fun liveStateEvents(eventTypes: Set): Flow> {
- return room.stateService().getStateEventsLive(eventTypes).asFlow()
+ fun liveStateEvents(eventTypes: Set, stateKey: QueryStateEventValue): Flow> {
+ return room.stateService().getStateEventsLive(eventTypes, stateKey).asFlow()
.startWith(room.coroutineDispatchers.io) {
- room.stateService().getStateEvents(eventTypes)
+ room.stateService().getStateEvents(eventTypes, stateKey)
}
}
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 2839e6ab61..f22cfa369a 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
@@ -19,15 +19,13 @@ package org.matrix.android.sdk.flow
import androidx.lifecycle.asFlow
import androidx.paging.PagedList
import kotlinx.coroutines.flow.Flow
-import org.matrix.android.sdk.api.query.QueryStringValue
+import org.matrix.android.sdk.api.query.QueryStateEventValue
import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.accountdata.UserAccountDataEvent
import org.matrix.android.sdk.api.session.crypto.crosssigning.MXCrossSigningInfo
import org.matrix.android.sdk.api.session.crypto.crosssigning.PrivateKeysInfo
import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo
-import org.matrix.android.sdk.api.session.group.GroupSummaryQueryParams
-import org.matrix.android.sdk.api.session.group.model.GroupSummary
import org.matrix.android.sdk.api.session.identity.ThreePid
import org.matrix.android.sdk.api.session.pushers.Pusher
import org.matrix.android.sdk.api.session.room.RoomSortOrder
@@ -59,13 +57,6 @@ class FlowSession(private val session: Session) {
}
}
- fun liveGroupSummaries(queryParams: GroupSummaryQueryParams): Flow> {
- return session.groupService().getGroupSummariesLive(queryParams).asFlow()
- .startWith(session.coroutineDispatchers.io) {
- session.groupService().getGroupSummaries(queryParams)
- }
- }
-
fun liveSpaceSummaries(queryParams: SpaceSummaryQueryParams): Flow> {
return session.spaceService().getSpaceSummariesLive(queryParams).asFlow()
.startWith(session.coroutineDispatchers.io) {
@@ -88,7 +79,7 @@ class FlowSession(private val session: Session) {
}
fun liveSyncState(): Flow {
- return session.getSyncStateLive().asFlow()
+ return session.syncService().getSyncStateLive().asFlow()
}
fun livePushers(): Flow> {
@@ -179,7 +170,7 @@ class FlowSession(private val session: Session) {
fun liveRoomWidgets(
roomId: String,
- widgetId: QueryStringValue,
+ widgetId: QueryStateEventValue,
widgetTypes: Set? = null,
excludedTypes: Set? = null
): Flow> {
diff --git a/matrix-sdk-android/build.gradle b/matrix-sdk-android/build.gradle
index fbed8442a9..e6b526585b 100644
--- a/matrix-sdk-android/build.gradle
+++ b/matrix-sdk-android/build.gradle
@@ -5,6 +5,10 @@ apply plugin: 'kotlin-parcelize'
apply plugin: 'realm-android'
apply plugin: "org.jetbrains.dokka"
+if (project.hasProperty("coverage")) {
+ apply plugin: 'jacoco'
+}
+
buildscript {
repositories {
// Do not use `mavenCentral()`, it prevents Dependabot from working properly
@@ -13,7 +17,7 @@ buildscript {
}
}
dependencies {
- classpath "io.realm:realm-gradle-plugin:10.9.0"
+ classpath "io.realm:realm-gradle-plugin:10.11.0"
}
}
@@ -56,7 +60,7 @@ android {
// that the app's state is completely cleared between tests.
testInstrumentationRunnerArguments clearPackageData: 'true'
- buildConfigField "String", "SDK_VERSION", "\"1.4.20\""
+ buildConfigField "String", "SDK_VERSION", "\"1.4.34\""
buildConfigField "String", "GIT_SDK_REVISION", "\"${gitRevision()}\""
buildConfigField "String", "GIT_SDK_REVISION_UNIX_DATE", "\"${gitRevisionUnixDate()}\""
@@ -74,7 +78,9 @@ android {
buildTypes {
debug {
- testCoverageEnabled true
+ if (project.hasProperty("coverage")) {
+ testCoverageEnabled = coverage.enableTestCoverage
+ }
// Set to true to log privacy or sensible data, such as token
buildConfigField "boolean", "LOG_PRIVATE_DATA", project.property("vector.debugPrivateData")
// Set to BODY instead of NONE to enable logging
@@ -152,7 +158,7 @@ dependencies {
// - https://github.com/square/okhttp/issues/3278
// - https://github.com/square/okhttp/issues/4455
// - https://github.com/square/okhttp/issues/3146
- implementation(platform("com.squareup.okhttp3:okhttp-bom:4.9.3"))
+ implementation(platform("com.squareup.okhttp3:okhttp-bom:4.10.0"))
implementation 'com.squareup.okhttp3:okhttp'
implementation 'com.squareup.okhttp3:logging-interceptor'
@@ -176,7 +182,7 @@ dependencies {
implementation libs.androidx.work
// olm lib is now hosted in MavenCentral
- implementation 'org.matrix.android:olm-sdk:3.2.11'
+ implementation 'org.matrix.android:olm-sdk:3.2.12'
// DI
implementation libs.dagger.dagger
@@ -193,7 +199,7 @@ dependencies {
implementation libs.apache.commonsImaging
// Phone number https://github.com/google/libphonenumber
- implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.49'
+ implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.53'
testImplementation libs.tests.junit
// Note: version sticks to 1.9.2 due to https://github.com/mockk/mockk/issues/281
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/session/securestorage/TestBuildVersionSdkIntProvider.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/TestBuildVersionSdkIntProvider.kt
similarity index 78%
rename from matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/session/securestorage/TestBuildVersionSdkIntProvider.kt
rename to matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/TestBuildVersionSdkIntProvider.kt
index b08c88fb24..d0d64491ef 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/session/securestorage/TestBuildVersionSdkIntProvider.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/TestBuildVersionSdkIntProvider.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 The Matrix.org Foundation C.I.C.
+ * 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.
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package org.matrix.android.sdk.internal.session.securestorage
+package org.matrix.android.sdk
-import org.matrix.android.sdk.internal.util.system.BuildVersionSdkIntProvider
+import org.matrix.android.sdk.api.util.BuildVersionSdkIntProvider
class TestBuildVersionSdkIntProvider : BuildVersionSdkIntProvider {
var value: Int = 0
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/session/securestorage/SecretStoringUtilsTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/api/securestorage/SecretStoringUtilsTest.kt
similarity index 62%
rename from matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/session/securestorage/SecretStoringUtilsTest.kt
rename to matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/api/securestorage/SecretStoringUtilsTest.kt
index 6bcd12742b..14f985243c 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/session/securestorage/SecretStoringUtilsTest.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/api/securestorage/SecretStoringUtilsTest.kt
@@ -14,40 +14,57 @@
* limitations under the License.
*/
-package org.matrix.android.sdk.internal.session.securestorage
+package org.matrix.android.sdk.api.securestorage
import android.os.Build
+import android.util.Base64
import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry
+import io.mockk.clearAllMocks
+import io.mockk.every
+import io.mockk.spyk
+import org.amshove.kluent.invoking
import org.amshove.kluent.shouldBeEqualTo
+import org.amshove.kluent.shouldBeInstanceOf
+import org.amshove.kluent.shouldNotThrow
+import org.amshove.kluent.shouldThrow
+import org.junit.Before
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
-import org.matrix.android.sdk.InstrumentedTest
-import org.matrix.android.sdk.api.util.fromBase64
-import org.matrix.android.sdk.api.util.toBase64NoPadding
+import org.matrix.android.sdk.TestBuildVersionSdkIntProvider
import java.io.ByteArrayOutputStream
+import java.security.KeyStore
+import java.security.KeyStoreException
import java.util.UUID
@RunWith(AndroidJUnit4::class)
@FixMethodOrder(MethodSorters.JVM)
-class SecretStoringUtilsTest : InstrumentedTest {
+class SecretStoringUtilsTest {
+ private val context = InstrumentationRegistry.getInstrumentation().targetContext
private val buildVersionSdkIntProvider = TestBuildVersionSdkIntProvider()
- private val secretStoringUtils = SecretStoringUtils(context(), buildVersionSdkIntProvider)
+ private val keyStore = spyk(KeyStore.getInstance("AndroidKeyStore")).also { it.load(null) }
+ private val secretStoringUtils = SecretStoringUtils(context, keyStore, buildVersionSdkIntProvider)
companion object {
const val TEST_STR = "This is something I want to store safely!"
}
+ @Before
+ fun setup() {
+ clearAllMocks()
+ }
+
@Test
fun testStringNominalCaseApi21() {
val alias = generateAlias()
buildVersionSdkIntProvider.value = Build.VERSION_CODES.LOLLIPOP
// Encrypt
- val encrypted = secretStoringUtils.securelyStoreString(TEST_STR, alias)
+ val encrypted = secretStoringUtils.securelyStoreBytes(TEST_STR.toByteArray(), alias)
// Decrypt
- val decrypted = secretStoringUtils.loadSecureSecret(encrypted, alias)
+ val decrypted = String(secretStoringUtils.loadSecureSecretBytes(encrypted, alias))
decrypted shouldBeEqualTo TEST_STR
secretStoringUtils.safeDeleteKey(alias)
}
@@ -57,9 +74,9 @@ class SecretStoringUtilsTest : InstrumentedTest {
val alias = generateAlias()
buildVersionSdkIntProvider.value = Build.VERSION_CODES.M
// Encrypt
- val encrypted = secretStoringUtils.securelyStoreString(TEST_STR, alias)
+ val encrypted = secretStoringUtils.securelyStoreBytes(TEST_STR.toByteArray(), alias)
// Decrypt
- val decrypted = secretStoringUtils.loadSecureSecret(encrypted, alias)
+ val decrypted = String(secretStoringUtils.loadSecureSecretBytes(encrypted, alias))
decrypted shouldBeEqualTo TEST_STR
secretStoringUtils.safeDeleteKey(alias)
}
@@ -69,9 +86,9 @@ class SecretStoringUtilsTest : InstrumentedTest {
val alias = generateAlias()
buildVersionSdkIntProvider.value = Build.VERSION_CODES.R
// Encrypt
- val encrypted = secretStoringUtils.securelyStoreString(TEST_STR, alias)
+ val encrypted = secretStoringUtils.securelyStoreBytes(TEST_STR.toByteArray(), alias)
// Decrypt
- val decrypted = secretStoringUtils.loadSecureSecret(encrypted, alias)
+ val decrypted = String(secretStoringUtils.loadSecureSecretBytes(encrypted, alias))
decrypted shouldBeEqualTo TEST_STR
secretStoringUtils.safeDeleteKey(alias)
}
@@ -81,13 +98,13 @@ class SecretStoringUtilsTest : InstrumentedTest {
val alias = generateAlias()
buildVersionSdkIntProvider.value = Build.VERSION_CODES.LOLLIPOP
// Encrypt
- val encrypted = secretStoringUtils.securelyStoreString(TEST_STR, alias)
+ val encrypted = secretStoringUtils.securelyStoreBytes(TEST_STR.toByteArray(), alias)
// Simulate a system upgrade
buildVersionSdkIntProvider.value = Build.VERSION_CODES.M
// Decrypt
- val decrypted = secretStoringUtils.loadSecureSecret(encrypted, alias)
+ val decrypted = String(secretStoringUtils.loadSecureSecretBytes(encrypted, alias))
decrypted shouldBeEqualTo TEST_STR
secretStoringUtils.safeDeleteKey(alias)
}
@@ -180,5 +197,56 @@ class SecretStoringUtilsTest : InstrumentedTest {
secretStoringUtils.safeDeleteKey(alias)
}
+ @Test
+ fun testEnsureKeyReturnsSymmetricKeyOnAndroidM() {
+ buildVersionSdkIntProvider.value = Build.VERSION_CODES.M
+ val alias = generateAlias()
+
+ val key = secretStoringUtils.ensureKey(alias)
+ key shouldBeInstanceOf KeyStore.SecretKeyEntry::class
+
+ secretStoringUtils.safeDeleteKey(alias)
+ }
+
+ @Test
+ fun testEnsureKeyReturnsPrivateKeyOnAndroidL() {
+ buildVersionSdkIntProvider.value = Build.VERSION_CODES.LOLLIPOP
+ val alias = generateAlias()
+
+ val key = secretStoringUtils.ensureKey(alias)
+ key shouldBeInstanceOf KeyStore.PrivateKeyEntry::class
+
+ secretStoringUtils.safeDeleteKey(alias)
+ }
+
+ @Test
+ fun testSafeDeleteCanHandleKeyStoreExceptions() {
+ every { keyStore.deleteEntry(any()) } throws KeyStoreException()
+
+ invoking { secretStoringUtils.safeDeleteKey(generateAlias()) } shouldNotThrow KeyStoreException::class
+ }
+
+ @Test
+ fun testLoadSecureSecretBytesWillThrowOnInvalidStreamFormat() {
+ invoking {
+ secretStoringUtils.loadSecureSecretBytes(byteArrayOf(255.toByte()), generateAlias())
+ } shouldThrow IllegalArgumentException::class
+ }
+
+ @Test
+ fun testLoadSecureSecretWillThrowOnInvalidStreamFormat() {
+ invoking {
+ secretStoringUtils.loadSecureSecret(byteArrayOf(255.toByte()).inputStream(), generateAlias())
+ } shouldThrow IllegalArgumentException::class
+ }
+
private fun generateAlias() = UUID.randomUUID().toString()
}
+
+private fun ByteArray.toBase64NoPadding(): String {
+ return Base64.encodeToString(this, Base64.NO_PADDING or Base64.NO_WRAP)
+}
+
+private fun String.fromBase64(): ByteArray {
+ return Base64.decode(this, Base64.DEFAULT)
+}
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 9160130bfa..a78953caac 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
@@ -18,12 +18,15 @@ package org.matrix.android.sdk.common
import android.content.Context
import android.net.Uri
+import android.util.Log
import androidx.lifecycle.Observer
import androidx.test.internal.runner.junit4.statement.UiThreadStatement
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
+import kotlinx.coroutines.cancel
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
@@ -38,7 +41,10 @@ import org.matrix.android.sdk.api.auth.registration.RegistrationResult
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.toModel
+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.model.Membership
import org.matrix.android.sdk.api.session.room.model.message.MessageContent
import org.matrix.android.sdk.api.session.room.send.SendState
import org.matrix.android.sdk.api.session.room.timeline.Timeline
@@ -47,6 +53,7 @@ import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings
import org.matrix.android.sdk.api.session.sync.SyncState
import timber.log.Timber
import java.util.UUID
+import java.util.concurrent.CancellationException
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
@@ -54,7 +61,7 @@ import java.util.concurrent.TimeUnit
* This class exposes methods to be used in common cases
* Registration, login, Sync, Sending messages...
*/
-class CommonTestHelper private constructor(context: Context) {
+class CommonTestHelper internal constructor(context: Context) {
companion object {
internal fun runSessionTest(context: Context, autoSignoutOnClose: Boolean = true, block: (CommonTestHelper) -> Unit) {
@@ -137,11 +144,11 @@ class CommonTestHelper private constructor(context: Context) {
fun syncSession(session: Session, timeout: Long = TestConstants.timeOutMillis * 10) {
val lock = CountDownLatch(1)
coroutineScope.launch {
- session.startSync(true)
- val syncLiveData = session.getSyncStateLive()
+ session.syncService().startSync(true)
+ val syncLiveData = session.syncService().getSyncStateLive()
val syncObserver = object : Observer {
override fun onChanged(t: SyncState?) {
- if (session.hasAlreadySynced()) {
+ if (session.syncService().hasAlreadySynced()) {
lock.countDown()
syncLiveData.removeObserver(this)
}
@@ -160,10 +167,10 @@ class CommonTestHelper private constructor(context: Context) {
fun clearCacheAndSync(session: Session, timeout: Long = TestConstants.timeOutMillis) {
waitWithLatch(timeout) { latch ->
session.clearCache()
- val syncLiveData = session.getSyncStateLive()
+ val syncLiveData = session.syncService().getSyncStateLive()
val syncObserver = object : Observer {
override fun onChanged(t: SyncState?) {
- if (session.hasAlreadySynced()) {
+ if (session.syncService().hasAlreadySynced()) {
Timber.v("Clear cache and synced")
syncLiveData.removeObserver(this)
latch.countDown()
@@ -171,7 +178,7 @@ class CommonTestHelper private constructor(context: Context) {
}
}
syncLiveData.observeForever(syncObserver)
- session.startSync(true)
+ session.syncService().startSync(true)
}
}
@@ -241,6 +248,37 @@ class CommonTestHelper private constructor(context: Context) {
return sentEvents
}
+ fun waitForAndAcceptInviteInRoom(otherSession: Session, roomID: String) {
+ waitWithLatch { latch ->
+ retryPeriodicallyWithLatch(latch) {
+ val roomSummary = otherSession.getRoomSummary(roomID)
+ (roomSummary != null && roomSummary.membership == Membership.INVITE).also {
+ if (it) {
+ Log.v("# TEST", "${otherSession.myUserId} can see the invite")
+ }
+ }
+ }
+ }
+
+ // not sure why it's taking so long :/
+ runBlockingTest(90_000) {
+ Log.v("#E2E TEST", "${otherSession.myUserId} tries to join room $roomID")
+ try {
+ otherSession.roomService().joinRoom(roomID)
+ } catch (ex: JoinRoomFailure.JoinedWithTimeout) {
+ // it's ok we will wait after
+ }
+ }
+
+ Log.v("#E2E TEST", "${otherSession.myUserId} waiting for join echo ...")
+ waitWithLatch {
+ retryPeriodicallyWithLatch(it) {
+ val roomSummary = otherSession.getRoomSummary(roomID)
+ roomSummary != null && roomSummary.membership == Membership.JOIN
+ }
+ }
+ }
+
/**
* Reply in a thread
* @param room the room where to send the messages
@@ -285,6 +323,8 @@ class CommonTestHelper private constructor(context: Context) {
)
assertNotNull(session)
return session.also {
+ // most of the test was created pre-MSC3061 so ensure compatibility
+ it.cryptoService().enableShareKeyOnInvite(false)
trackedSessions.add(session)
}
}
@@ -428,16 +468,26 @@ class CommonTestHelper private constructor(context: Context) {
* @param latch
* @throws InterruptedException
*/
- fun await(latch: CountDownLatch, timeout: Long? = TestConstants.timeOutMillis) {
+ fun await(latch: CountDownLatch, timeout: Long? = TestConstants.timeOutMillis, job: Job? = null) {
assertTrue(
"Timed out after " + timeout + "ms waiting for something to happen. See stacktrace for cause.",
- latch.await(timeout ?: TestConstants.timeOutMillis, TimeUnit.MILLISECONDS)
+ latch.await(timeout ?: TestConstants.timeOutMillis, TimeUnit.MILLISECONDS).also {
+ if (!it) {
+ // cancel job on timeout
+ job?.cancel("Await timeout")
+ }
+ }
)
}
suspend fun retryPeriodicallyWithLatch(latch: CountDownLatch, condition: (() -> Boolean)) {
while (true) {
- delay(1000)
+ try {
+ delay(1000)
+ } catch (ex: CancellationException) {
+ // the job was canceled, just stop
+ return
+ }
if (condition()) {
latch.countDown()
return
@@ -447,10 +497,10 @@ class CommonTestHelper private constructor(context: Context) {
fun waitWithLatch(timeout: Long? = TestConstants.timeOutMillis, dispatcher: CoroutineDispatcher = Dispatchers.Main, block: suspend (CountDownLatch) -> Unit) {
val latch = CountDownLatch(1)
- coroutineScope.launch(dispatcher) {
+ val job = coroutineScope.launch(dispatcher) {
block(latch)
}
- await(latch, timeout)
+ await(latch, timeout, job)
}
fun runBlockingTest(timeout: Long = TestConstants.timeOutMillis, block: suspend () -> T): T {
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 5fd86d4fdb..f36bfb6210 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
@@ -53,6 +53,7 @@ import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.getRoom
import org.matrix.android.sdk.api.session.room.Room
import org.matrix.android.sdk.api.session.room.model.Membership
+import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibility
import org.matrix.android.sdk.api.session.room.model.RoomSummary
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
import org.matrix.android.sdk.api.session.room.model.message.MessageContent
@@ -76,11 +77,14 @@ class CryptoTestHelper(val testHelper: CommonTestHelper) {
/**
* @return alice session
*/
- fun doE2ETestWithAliceInARoom(encryptedRoom: Boolean = true): CryptoTestData {
+ fun doE2ETestWithAliceInARoom(encryptedRoom: Boolean = true, roomHistoryVisibility: RoomHistoryVisibility? = null): CryptoTestData {
val aliceSession = testHelper.createAccount(TestConstants.USER_ALICE, defaultSessionParams)
val roomId = testHelper.runBlockingTest {
- aliceSession.roomService().createRoom(CreateRoomParams().apply { name = "MyRoom" })
+ aliceSession.roomService().createRoom(CreateRoomParams().apply {
+ historyVisibility = roomHistoryVisibility
+ name = "MyRoom"
+ })
}
if (encryptedRoom) {
testHelper.waitWithLatch { latch ->
@@ -104,8 +108,8 @@ class CryptoTestHelper(val testHelper: CommonTestHelper) {
/**
* @return alice and bob sessions
*/
- fun doE2ETestWithAliceAndBobInARoom(encryptedRoom: Boolean = true): CryptoTestData {
- val cryptoTestData = doE2ETestWithAliceInARoom(encryptedRoom)
+ fun doE2ETestWithAliceAndBobInARoom(encryptedRoom: Boolean = true, roomHistoryVisibility: RoomHistoryVisibility? = null): CryptoTestData {
+ val cryptoTestData = doE2ETestWithAliceInARoom(encryptedRoom, roomHistoryVisibility)
val aliceSession = cryptoTestData.firstSession
val aliceRoomId = cryptoTestData.roomId
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/TestMatrixComponent.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/TestMatrixComponent.kt
index daf6b73313..6cf01d4ae2 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/TestMatrixComponent.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/TestMatrixComponent.kt
@@ -20,7 +20,9 @@ import android.content.Context
import dagger.BindsInstance
import dagger.Component
import org.matrix.android.sdk.api.MatrixConfiguration
+import org.matrix.android.sdk.api.securestorage.SecureStorageModule
import org.matrix.android.sdk.internal.auth.AuthModule
+import org.matrix.android.sdk.internal.debug.DebugModule
import org.matrix.android.sdk.internal.di.MatrixComponent
import org.matrix.android.sdk.internal.di.MatrixModule
import org.matrix.android.sdk.internal.di.MatrixScope
@@ -36,8 +38,10 @@ import org.matrix.android.sdk.internal.util.system.SystemModule
NetworkModule::class,
AuthModule::class,
RawModule::class,
+ DebugModule::class,
SettingsModule::class,
- SystemModule::class
+ SystemModule::class,
+ SecureStorageModule::class,
]
)
@MatrixScope
@@ -49,7 +53,7 @@ internal interface TestMatrixComponent : MatrixComponent {
interface Factory {
fun create(
@BindsInstance context: Context,
- @BindsInstance matrixConfiguration: MatrixConfiguration
+ @BindsInstance matrixConfiguration: MatrixConfiguration,
): TestMatrixComponent
}
}
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/E2EShareKeysConfigTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/E2EShareKeysConfigTest.kt
new file mode 100644
index 0000000000..32d63a1934
--- /dev/null
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/E2EShareKeysConfigTest.kt
@@ -0,0 +1,298 @@
+/*
+ * Copyright 2022 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.internal.crypto
+
+import android.util.Log
+import androidx.test.filters.LargeTest
+import org.amshove.kluent.internal.assertEquals
+import org.junit.Assert
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.junit.runners.MethodSorters
+import org.matrix.android.sdk.InstrumentedTest
+import org.matrix.android.sdk.api.session.Session
+import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysVersion
+import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysVersionResult
+import org.matrix.android.sdk.api.session.crypto.keysbackup.MegolmBackupCreationInfo
+import org.matrix.android.sdk.api.session.crypto.model.ImportRoomKeysResult
+import org.matrix.android.sdk.api.session.getRoom
+import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibility
+import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
+import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
+import org.matrix.android.sdk.common.CommonTestHelper
+import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest
+import org.matrix.android.sdk.common.CryptoTestData
+import org.matrix.android.sdk.common.SessionTestParams
+import org.matrix.android.sdk.common.TestConstants
+import org.matrix.android.sdk.common.TestMatrixCallback
+
+@RunWith(JUnit4::class)
+@FixMethodOrder(MethodSorters.JVM)
+@LargeTest
+class E2EShareKeysConfigTest : InstrumentedTest {
+
+ @Test
+ fun msc3061ShouldBeDisabledByDefault() = runCryptoTest(context()) { _, commonTestHelper ->
+ val aliceSession = commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(withInitialSync = false))
+ Assert.assertFalse("MSC3061 is lab and should be disabled by default", aliceSession.cryptoService().isShareKeysOnInviteEnabled())
+ }
+
+ @Test
+ fun ensureKeysAreNotSharedIfOptionDisabled() = runCryptoTest(context()) { cryptoTestHelper, commonTestHelper ->
+ val aliceSession = commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(withInitialSync = true))
+ aliceSession.cryptoService().enableShareKeyOnInvite(false)
+ val roomId = commonTestHelper.runBlockingTest {
+ aliceSession.roomService().createRoom(CreateRoomParams().apply {
+ historyVisibility = RoomHistoryVisibility.SHARED
+ name = "MyRoom"
+ enableEncryption()
+ })
+ }
+
+ commonTestHelper.waitWithLatch { latch ->
+ commonTestHelper.retryPeriodicallyWithLatch(latch) {
+ aliceSession.roomService().getRoomSummary(roomId)?.isEncrypted == true
+ }
+ }
+ val roomAlice = aliceSession.roomService().getRoom(roomId)!!
+
+ // send some messages
+ val withSession1 = commonTestHelper.sendTextMessage(roomAlice, "Hello", 1)
+ aliceSession.cryptoService().discardOutboundSession(roomId)
+ val withSession2 = commonTestHelper.sendTextMessage(roomAlice, "World", 1)
+
+ // Create bob account
+ val bobSession = commonTestHelper.createAccount(TestConstants.USER_BOB, SessionTestParams(withInitialSync = true))
+
+ // Let alice invite bob
+ commonTestHelper.runBlockingTest {
+ roomAlice.membershipService().invite(bobSession.myUserId)
+ }
+
+ commonTestHelper.waitForAndAcceptInviteInRoom(bobSession, roomId)
+
+ // Bob has join but should not be able to decrypt history
+ cryptoTestHelper.ensureCannotDecrypt(
+ withSession1.map { it.eventId } + withSession2.map { it.eventId },
+ bobSession,
+ roomId
+ )
+
+ // We don't need bob anymore
+ commonTestHelper.signOutAndClose(bobSession)
+
+ // Now let's enable history key sharing on alice side
+ aliceSession.cryptoService().enableShareKeyOnInvite(true)
+
+ // let's add a new message first
+ val afterFlagOn = commonTestHelper.sendTextMessage(roomAlice, "After", 1)
+
+ // Worth nothing to check that the session was rotated
+ Assert.assertNotEquals(
+ "Session should have been rotated",
+ withSession2.first().root.content?.get("session_id")!!,
+ afterFlagOn.first().root.content?.get("session_id")!!
+ )
+
+ // Invite a new user
+ val samSession = commonTestHelper.createAccount(TestConstants.USER_SAM, SessionTestParams(withInitialSync = true))
+
+ // Let alice invite sam
+ commonTestHelper.runBlockingTest {
+ roomAlice.membershipService().invite(samSession.myUserId)
+ }
+
+ commonTestHelper.waitForAndAcceptInviteInRoom(samSession, roomId)
+
+ // Sam shouldn't be able to decrypt messages with the first session, but should decrypt the one with 3rd session
+ cryptoTestHelper.ensureCannotDecrypt(
+ withSession1.map { it.eventId } + withSession2.map { it.eventId },
+ samSession,
+ roomId
+ )
+
+ cryptoTestHelper.ensureCanDecrypt(
+ afterFlagOn.map { it.eventId },
+ samSession,
+ roomId,
+ afterFlagOn.map { it.root.getClearContent()?.get("body") as String })
+ }
+
+ @Test
+ fun ifSharingDisabledOnAliceSideBobShouldNotShareAliceHistoty() = runCryptoTest(context()) { cryptoTestHelper, commonTestHelper ->
+ val testData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(roomHistoryVisibility = RoomHistoryVisibility.SHARED)
+ val aliceSession = testData.firstSession.also {
+ it.cryptoService().enableShareKeyOnInvite(false)
+ }
+ val bobSession = testData.secondSession!!.also {
+ it.cryptoService().enableShareKeyOnInvite(true)
+ }
+
+ val (fromAliceNotSharable, fromBobSharable, samSession) = commonAliceAndBobSendMessages(commonTestHelper, aliceSession, testData, bobSession)
+
+ // Bob should have shared history keys to sam.
+ // But has alice hasn't enabled sharing, bob shouldn't send her sessions
+ cryptoTestHelper.ensureCannotDecrypt(
+ fromAliceNotSharable.map { it.eventId },
+ samSession,
+ testData.roomId
+ )
+
+ cryptoTestHelper.ensureCanDecrypt(
+ fromBobSharable.map { it.eventId },
+ samSession,
+ testData.roomId,
+ fromBobSharable.map { it.root.getClearContent()?.get("body") as String })
+ }
+
+ @Test
+ fun ifSharingEnabledOnAliceSideBobShouldShareAliceHistoty() = runCryptoTest(context()) { cryptoTestHelper, commonTestHelper ->
+ val testData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(roomHistoryVisibility = RoomHistoryVisibility.SHARED)
+ val aliceSession = testData.firstSession.also {
+ it.cryptoService().enableShareKeyOnInvite(true)
+ }
+ val bobSession = testData.secondSession!!.also {
+ it.cryptoService().enableShareKeyOnInvite(true)
+ }
+
+ val (fromAliceNotSharable, fromBobSharable, samSession) = commonAliceAndBobSendMessages(commonTestHelper, aliceSession, testData, bobSession)
+
+ cryptoTestHelper.ensureCanDecrypt(
+ fromAliceNotSharable.map { it.eventId },
+ samSession,
+ testData.roomId,
+ fromAliceNotSharable.map { it.root.getClearContent()?.get("body") as String })
+
+ cryptoTestHelper.ensureCanDecrypt(
+ fromBobSharable.map { it.eventId },
+ samSession,
+ testData.roomId,
+ fromBobSharable.map { it.root.getClearContent()?.get("body") as String })
+ }
+
+ private fun commonAliceAndBobSendMessages(commonTestHelper: CommonTestHelper, aliceSession: Session, testData: CryptoTestData, bobSession: Session): Triple, List, Session> {
+ val fromAliceNotSharable = commonTestHelper.sendTextMessage(aliceSession.getRoom(testData.roomId)!!, "Hello from alice", 1)
+ val fromBobSharable = commonTestHelper.sendTextMessage(bobSession.getRoom(testData.roomId)!!, "Hello from bob", 1)
+
+ // Now let bob invite Sam
+ // Invite a new user
+ val samSession = commonTestHelper.createAccount(TestConstants.USER_SAM, SessionTestParams(withInitialSync = true))
+
+ // Let bob invite sam
+ commonTestHelper.runBlockingTest {
+ bobSession.getRoom(testData.roomId)!!.membershipService().invite(samSession.myUserId)
+ }
+
+ commonTestHelper.waitForAndAcceptInviteInRoom(samSession, testData.roomId)
+ return Triple(fromAliceNotSharable, fromBobSharable, samSession)
+ }
+
+ // test flag on backup is correct
+
+ @Test
+ fun testBackupFlagIsCorrect() = runCryptoTest(context()) { cryptoTestHelper, commonTestHelper ->
+ val aliceSession = commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(withInitialSync = true))
+ aliceSession.cryptoService().enableShareKeyOnInvite(false)
+ val roomId = commonTestHelper.runBlockingTest {
+ aliceSession.roomService().createRoom(CreateRoomParams().apply {
+ historyVisibility = RoomHistoryVisibility.SHARED
+ name = "MyRoom"
+ enableEncryption()
+ })
+ }
+
+ commonTestHelper.waitWithLatch { latch ->
+ commonTestHelper.retryPeriodicallyWithLatch(latch) {
+ aliceSession.roomService().getRoomSummary(roomId)?.isEncrypted == true
+ }
+ }
+ val roomAlice = aliceSession.roomService().getRoom(roomId)!!
+
+ // send some messages
+ val notSharableMessage = commonTestHelper.sendTextMessage(roomAlice, "Hello", 1)
+ aliceSession.cryptoService().enableShareKeyOnInvite(true)
+ val sharableMessage = commonTestHelper.sendTextMessage(roomAlice, "World", 1)
+
+ Log.v("#E2E TEST", "Create and start key backup for bob ...")
+ val keysBackupService = aliceSession.cryptoService().keysBackupService()
+ val keyBackupPassword = "FooBarBaz"
+ val megolmBackupCreationInfo = commonTestHelper.doSync {
+ keysBackupService.prepareKeysBackupVersion(keyBackupPassword, null, it)
+ }
+ val version = commonTestHelper.doSync {
+ keysBackupService.createKeysBackupVersion(megolmBackupCreationInfo, it)
+ }
+
+ commonTestHelper.waitWithLatch { latch ->
+ keysBackupService.backupAllGroupSessions(
+ null,
+ TestMatrixCallback(latch, true)
+ )
+ }
+
+ // signout
+ commonTestHelper.signOutAndClose(aliceSession)
+
+ val newAliceSession = commonTestHelper.logIntoAccount(aliceSession.myUserId, SessionTestParams(true))
+ newAliceSession.cryptoService().enableShareKeyOnInvite(true)
+
+ newAliceSession.cryptoService().keysBackupService().let { kbs ->
+ val keyVersionResult = commonTestHelper.doSync {
+ kbs.getVersion(version.version, it)
+ }
+
+ val importedResult = commonTestHelper.doSync {
+ kbs.restoreKeyBackupWithPassword(
+ keyVersionResult!!,
+ keyBackupPassword,
+ null,
+ null,
+ null,
+ it
+ )
+ }
+
+ assertEquals(2, importedResult.totalNumberOfKeys)
+ }
+
+ // Now let's invite sam
+ // Invite a new user
+ val samSession = commonTestHelper.createAccount(TestConstants.USER_SAM, SessionTestParams(withInitialSync = true))
+
+ // Let alice invite sam
+ commonTestHelper.runBlockingTest {
+ newAliceSession.getRoom(roomId)!!.membershipService().invite(samSession.myUserId)
+ }
+
+ commonTestHelper.waitForAndAcceptInviteInRoom(samSession, roomId)
+
+ // Sam shouldn't be able to decrypt messages with the first session, but should decrypt the one with 3rd session
+ cryptoTestHelper.ensureCannotDecrypt(
+ notSharableMessage.map { it.eventId },
+ samSession,
+ roomId
+ )
+
+ cryptoTestHelper.ensureCanDecrypt(
+ sharableMessage.map { it.eventId },
+ samSession,
+ roomId,
+ sharableMessage.map { it.root.getClearContent()?.get("body") as String })
+ }
+}
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 010383dab8..251c13ccbf 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/E2eeSanityTests.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/E2eeSanityTests.kt
@@ -23,7 +23,6 @@ import org.amshove.kluent.fail
import org.amshove.kluent.internal.assertEquals
import org.junit.Assert
import org.junit.FixMethodOrder
-import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -49,9 +48,7 @@ import org.matrix.android.sdk.api.session.events.model.content.EncryptedEventCon
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.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
@@ -67,10 +64,10 @@ import org.matrix.android.sdk.common.TestMatrixCallback
import org.matrix.android.sdk.mustFail
import java.util.concurrent.CountDownLatch
+// @Ignore("This test fails with an unhandled exception thrown from a coroutine which terminates the entire test run.")
@RunWith(JUnit4::class)
@FixMethodOrder(MethodSorters.JVM)
@LargeTest
-@Ignore("This test fails with an unhandled exception thrown from a coroutine which terminates the entire test run.")
class E2eeSanityTests : InstrumentedTest {
@get:Rule val rule = RetryTestRule(3)
@@ -115,7 +112,7 @@ class E2eeSanityTests : InstrumentedTest {
// All user should accept invite
otherAccounts.forEach { otherSession ->
- waitForAndAcceptInviteInRoom(testHelper, otherSession, e2eRoomID)
+ testHelper.waitForAndAcceptInviteInRoom(otherSession, e2eRoomID)
Log.v("#E2E TEST", "${otherSession.myUserId} joined room $e2eRoomID")
}
@@ -156,7 +153,7 @@ class E2eeSanityTests : InstrumentedTest {
}
newAccount.forEach {
- waitForAndAcceptInviteInRoom(testHelper, it, e2eRoomID)
+ testHelper.waitForAndAcceptInviteInRoom(it, e2eRoomID)
}
ensureMembersHaveJoined(testHelper, aliceSession, newAccount, e2eRoomID)
@@ -626,7 +623,7 @@ class E2eeSanityTests : InstrumentedTest {
// we can release this latch?
oldCompleteLatch.countDown()
}
- else -> Unit
+ else -> Unit
}
}
})
@@ -653,17 +650,17 @@ class E2eeSanityTests : InstrumentedTest {
IncomingSasVerificationTransaction.UxState.SHOW_ACCEPT -> {
// no need to accept as there was a request first it will auto accept
}
- IncomingSasVerificationTransaction.UxState.SHOW_SAS -> {
+ IncomingSasVerificationTransaction.UxState.SHOW_SAS -> {
if (matchOnce) {
sasTx.userHasVerifiedShortCode()
newCode = sasTx.getDecimalCodeRepresentation()
matchOnce = false
}
}
- IncomingSasVerificationTransaction.UxState.VERIFIED -> {
+ IncomingSasVerificationTransaction.UxState.VERIFIED -> {
newCompleteLatch.countDown()
}
- else -> Unit
+ else -> Unit
}
}
})
@@ -740,37 +737,6 @@ class E2eeSanityTests : InstrumentedTest {
}
}
- private fun waitForAndAcceptInviteInRoom(testHelper: CommonTestHelper, otherSession: Session, e2eRoomID: String) {
- testHelper.waitWithLatch { latch ->
- testHelper.retryPeriodicallyWithLatch(latch) {
- val roomSummary = otherSession.getRoomSummary(e2eRoomID)
- (roomSummary != null && roomSummary.membership == Membership.INVITE).also {
- if (it) {
- Log.v("#E2E TEST", "${otherSession.myUserId} can see the invite from alice")
- }
- }
- }
- }
-
- // not sure why it's taking so long :/
- testHelper.runBlockingTest(90_000) {
- Log.v("#E2E TEST", "${otherSession.myUserId} tries to join room $e2eRoomID")
- try {
- otherSession.roomService().joinRoom(e2eRoomID)
- } catch (ex: JoinRoomFailure.JoinedWithTimeout) {
- // it's ok we will wait after
- }
- }
-
- Log.v("#E2E TEST", "${otherSession.myUserId} waiting for join echo ...")
- testHelper.waitWithLatch {
- testHelper.retryPeriodicallyWithLatch(it) {
- val roomSummary = otherSession.getRoomSummary(e2eRoomID)
- roomSummary != null && roomSummary.membership == Membership.JOIN
- }
- }
- }
-
private fun ensureIsDecrypted(testHelper: CommonTestHelper, sentEventIds: List, session: Session, e2eRoomID: String) {
testHelper.waitWithLatch { latch ->
sentEventIds.forEach { sentEventId ->
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/E2eeShareKeysHistoryTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/E2eeShareKeysHistoryTest.kt
new file mode 100644
index 0000000000..32a95008b1
--- /dev/null
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/E2eeShareKeysHistoryTest.kt
@@ -0,0 +1,424 @@
+/*
+ * Copyright 2022 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.internal.crypto
+
+import android.util.Log
+import androidx.test.filters.LargeTest
+import org.amshove.kluent.internal.assertEquals
+import org.amshove.kluent.internal.assertNotEquals
+import org.junit.Assert
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.junit.runners.MethodSorters
+import org.matrix.android.sdk.InstrumentedTest
+import org.matrix.android.sdk.api.query.QueryStringValue
+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.room.Room
+import org.matrix.android.sdk.api.session.room.failure.JoinRoomFailure
+import org.matrix.android.sdk.api.session.room.model.Membership
+import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibility
+import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibilityContent
+import org.matrix.android.sdk.api.session.room.model.shouldShareHistory
+import org.matrix.android.sdk.common.CommonTestHelper
+import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest
+import org.matrix.android.sdk.common.CryptoTestHelper
+import org.matrix.android.sdk.common.SessionTestParams
+
+@RunWith(JUnit4::class)
+@FixMethodOrder(MethodSorters.JVM)
+@LargeTest
+class E2eeShareKeysHistoryTest : InstrumentedTest {
+
+ @Test
+ fun testShareMessagesHistoryWithRoomWorldReadable() {
+ testShareHistoryWithRoomVisibility(RoomHistoryVisibility.WORLD_READABLE)
+ }
+
+ @Test
+ fun testShareMessagesHistoryWithRoomShared() {
+ testShareHistoryWithRoomVisibility(RoomHistoryVisibility.SHARED)
+ }
+
+ @Test
+ fun testShareMessagesHistoryWithRoomJoined() {
+ testShareHistoryWithRoomVisibility(RoomHistoryVisibility.JOINED)
+ }
+
+ @Test
+ fun testShareMessagesHistoryWithRoomInvited() {
+ testShareHistoryWithRoomVisibility(RoomHistoryVisibility.INVITED)
+ }
+
+ /**
+ * In this test we create a room and test that new members
+ * can decrypt history when the room visibility is
+ * RoomHistoryVisibility.SHARED or RoomHistoryVisibility.WORLD_READABLE.
+ * We should not be able to view messages/decrypt otherwise
+ */
+ private fun testShareHistoryWithRoomVisibility(roomHistoryVisibility: RoomHistoryVisibility? = null) =
+ runCryptoTest(context()) { cryptoTestHelper, testHelper ->
+ val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true, roomHistoryVisibility)
+
+ val e2eRoomID = cryptoTestData.roomId
+
+ // Alice
+ val aliceSession = cryptoTestData.firstSession.also {
+ it.cryptoService().enableShareKeyOnInvite(true)
+ }
+ val aliceRoomPOV = aliceSession.roomService().getRoom(e2eRoomID)!!
+
+ // Bob
+ val bobSession = cryptoTestData.secondSession!!.also {
+ it.cryptoService().enableShareKeyOnInvite(true)
+ }
+ val bobRoomPOV = bobSession.roomService().getRoom(e2eRoomID)!!
+
+ assertEquals(bobRoomPOV.roomSummary()?.joinedMembersCount, 2)
+ Log.v("#E2E TEST", "Alice and Bob are in roomId: $e2eRoomID")
+
+ val aliceMessageId: String? = sendMessageInRoom(aliceRoomPOV, "Hello Bob, I am Alice!", testHelper)
+ Assert.assertTrue("Message should be sent", aliceMessageId != null)
+ Log.v("#E2E TEST", "Alice sent message to roomId: $e2eRoomID")
+
+ // Bob should be able to decrypt the message
+ testHelper.waitWithLatch { latch ->
+ testHelper.retryPeriodicallyWithLatch(latch) {
+ val timelineEvent = bobSession.roomService().getRoom(e2eRoomID)?.timelineService()?.getTimelineEvent(aliceMessageId!!)
+ (timelineEvent != null &&
+ timelineEvent.isEncrypted() &&
+ timelineEvent.root.getClearType() == EventType.MESSAGE).also {
+ if (it) {
+ Log.v("#E2E TEST", "Bob can decrypt the message: ${timelineEvent?.root?.getDecryptedTextSummary()}")
+ }
+ }
+ }
+ }
+
+ // Create a new user
+ val arisSession = testHelper.createAccount("aris", SessionTestParams(true)).also {
+ it.cryptoService().enableShareKeyOnInvite(true)
+ }
+ Log.v("#E2E TEST", "Aris user created")
+
+ // Alice invites new user to the room
+ testHelper.runBlockingTest {
+ Log.v("#E2E TEST", "Alice invites ${arisSession.myUserId}")
+ aliceRoomPOV.membershipService().invite(arisSession.myUserId)
+ }
+
+ waitForAndAcceptInviteInRoom(arisSession, e2eRoomID, testHelper)
+
+ ensureMembersHaveJoined(aliceSession, arrayListOf(arisSession), e2eRoomID, testHelper)
+ Log.v("#E2E TEST", "Aris has joined roomId: $e2eRoomID")
+
+ when (roomHistoryVisibility) {
+ RoomHistoryVisibility.WORLD_READABLE,
+ RoomHistoryVisibility.SHARED,
+ null
+ -> {
+ // Aris should be able to decrypt the message
+ testHelper.waitWithLatch { latch ->
+ testHelper.retryPeriodicallyWithLatch(latch) {
+ val timelineEvent = arisSession.roomService().getRoom(e2eRoomID)?.timelineService()?.getTimelineEvent(aliceMessageId!!)
+ (timelineEvent != null &&
+ timelineEvent.isEncrypted() &&
+ timelineEvent.root.getClearType() == EventType.MESSAGE
+ ).also {
+ if (it) {
+ Log.v("#E2E TEST", "Aris can decrypt the message: ${timelineEvent?.root?.getDecryptedTextSummary()}")
+ }
+ }
+ }
+ }
+ }
+ RoomHistoryVisibility.INVITED,
+ RoomHistoryVisibility.JOINED -> {
+ // Aris should not even be able to get the message
+ testHelper.waitWithLatch { latch ->
+ testHelper.retryPeriodicallyWithLatch(latch) {
+ val timelineEvent = arisSession.roomService().getRoom(e2eRoomID)
+ ?.timelineService()
+ ?.getTimelineEvent(aliceMessageId!!)
+ timelineEvent == null
+ }
+ }
+ }
+ }
+
+ testHelper.signOutAndClose(arisSession)
+ cryptoTestData.cleanUp(testHelper)
+ }
+
+ @Test
+ fun testNeedsRotationFromWorldReadableToShared() {
+ testRotationDueToVisibilityChange(RoomHistoryVisibility.WORLD_READABLE, RoomHistoryVisibilityContent("shared"))
+ }
+
+ @Test
+ fun testNeedsRotationFromWorldReadableToInvited() {
+ testRotationDueToVisibilityChange(RoomHistoryVisibility.WORLD_READABLE, RoomHistoryVisibilityContent("invited"))
+ }
+
+ @Test
+ fun testNeedsRotationFromWorldReadableToJoined() {
+ testRotationDueToVisibilityChange(RoomHistoryVisibility.WORLD_READABLE, RoomHistoryVisibilityContent("joined"))
+ }
+
+ @Test
+ fun testNeedsRotationFromSharedToWorldReadable() {
+ testRotationDueToVisibilityChange(RoomHistoryVisibility.SHARED, RoomHistoryVisibilityContent("world_readable"))
+ }
+
+ @Test
+ fun testNeedsRotationFromSharedToInvited() {
+ testRotationDueToVisibilityChange(RoomHistoryVisibility.SHARED, RoomHistoryVisibilityContent("invited"))
+ }
+
+ @Test
+ fun testNeedsRotationFromSharedToJoined() {
+ testRotationDueToVisibilityChange(RoomHistoryVisibility.SHARED, RoomHistoryVisibilityContent("joined"))
+ }
+
+ @Test
+ fun testNeedsRotationFromInvitedToShared() {
+ testRotationDueToVisibilityChange(RoomHistoryVisibility.WORLD_READABLE, RoomHistoryVisibilityContent("shared"))
+ }
+
+ @Test
+ fun testNeedsRotationFromInvitedToWorldReadable() {
+ testRotationDueToVisibilityChange(RoomHistoryVisibility.WORLD_READABLE, RoomHistoryVisibilityContent("world_readable"))
+ }
+
+ @Test
+ fun testNeedsRotationFromInvitedToJoined() {
+ testRotationDueToVisibilityChange(RoomHistoryVisibility.WORLD_READABLE, RoomHistoryVisibilityContent("joined"))
+ }
+
+ @Test
+ fun testNeedsRotationFromJoinedToShared() {
+ testRotationDueToVisibilityChange(RoomHistoryVisibility.WORLD_READABLE, RoomHistoryVisibilityContent("shared"))
+ }
+
+ @Test
+ fun testNeedsRotationFromJoinedToInvited() {
+ testRotationDueToVisibilityChange(RoomHistoryVisibility.WORLD_READABLE, RoomHistoryVisibilityContent("invited"))
+ }
+
+ @Test
+ fun testNeedsRotationFromJoinedToWorldReadable() {
+ testRotationDueToVisibilityChange(RoomHistoryVisibility.WORLD_READABLE, RoomHistoryVisibilityContent("world_readable"))
+ }
+
+ /**
+ * In this test we will test that a rotation is needed when
+ * When the room's history visibility setting changes to world_readable or shared
+ * from invited or joined, or changes to invited or joined from world_readable or shared,
+ * senders that support this flag must rotate their megolm sessions.
+ */
+ private fun testRotationDueToVisibilityChange(
+ initRoomHistoryVisibility: RoomHistoryVisibility,
+ nextRoomHistoryVisibility: RoomHistoryVisibilityContent
+ ) {
+ val testHelper = CommonTestHelper(context())
+ val cryptoTestHelper = CryptoTestHelper(testHelper)
+
+ val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true, initRoomHistoryVisibility)
+ val e2eRoomID = cryptoTestData.roomId
+
+ // Alice
+ val aliceSession = cryptoTestData.firstSession.also {
+ it.cryptoService().enableShareKeyOnInvite(true)
+ }
+ val aliceRoomPOV = aliceSession.roomService().getRoom(e2eRoomID)!!
+// val aliceCryptoStore = (aliceSession.cryptoService() as DefaultCryptoService).cryptoStoreForTesting
+
+ // Bob
+ val bobSession = cryptoTestData.secondSession!!
+
+ val bobRoomPOV = bobSession.roomService().getRoom(e2eRoomID)!!
+
+ assertEquals(bobRoomPOV.roomSummary()?.joinedMembersCount, 2)
+ Log.v("#E2E TEST ROTATION", "Alice and Bob are in roomId: $e2eRoomID")
+
+ val aliceMessageId: String? = sendMessageInRoom(aliceRoomPOV, "Hello Bob, I am Alice!", testHelper)
+ Assert.assertTrue("Message should be sent", aliceMessageId != null)
+ Log.v("#E2E TEST ROTATION", "Alice sent message to roomId: $e2eRoomID")
+
+ // Bob should be able to decrypt the message
+ var firstAliceMessageMegolmSessionId: String? = null
+ val bobRoomPov = bobSession.roomService().getRoom(e2eRoomID)
+ testHelper.waitWithLatch { latch ->
+ testHelper.retryPeriodicallyWithLatch(latch) {
+ val timelineEvent = bobRoomPov
+ ?.timelineService()
+ ?.getTimelineEvent(aliceMessageId!!)
+ (timelineEvent != null &&
+ timelineEvent.isEncrypted() &&
+ timelineEvent.root.getClearType() == EventType.MESSAGE).also {
+ if (it) {
+ firstAliceMessageMegolmSessionId = timelineEvent?.root?.content?.get("session_id") as? String
+ Log.v(
+ "#E2E TEST",
+ "Bob can decrypt the message (sid:$firstAliceMessageMegolmSessionId): ${timelineEvent?.root?.getDecryptedTextSummary()}"
+ )
+ }
+ }
+ }
+ }
+
+ Assert.assertNotNull("megolm session id can't be null", firstAliceMessageMegolmSessionId)
+
+ var secondAliceMessageSessionId: String? = null
+ sendMessageInRoom(aliceRoomPOV, "Other msg", testHelper)?.let { secondMessage ->
+ testHelper.waitWithLatch { latch ->
+ testHelper.retryPeriodicallyWithLatch(latch) {
+ val timelineEvent = bobRoomPov
+ ?.timelineService()
+ ?.getTimelineEvent(secondMessage)
+ (timelineEvent != null &&
+ timelineEvent.isEncrypted() &&
+ timelineEvent.root.getClearType() == EventType.MESSAGE).also {
+ if (it) {
+ secondAliceMessageSessionId = timelineEvent?.root?.content?.get("session_id") as? String
+ Log.v(
+ "#E2E TEST",
+ "Bob can decrypt the message (sid:$secondAliceMessageSessionId): ${timelineEvent?.root?.getDecryptedTextSummary()}"
+ )
+ }
+ }
+ }
+ }
+ }
+ assertEquals("No rotation needed session should be the same", firstAliceMessageMegolmSessionId, secondAliceMessageSessionId)
+ Log.v("#E2E TEST ROTATION", "No rotation needed yet")
+
+ // Let's change the room history visibility
+ testHelper.runBlockingTest {
+ aliceRoomPOV.stateService()
+ .sendStateEvent(
+ eventType = EventType.STATE_ROOM_HISTORY_VISIBILITY,
+ stateKey = "",
+ body = RoomHistoryVisibilityContent(
+ historyVisibilityStr = nextRoomHistoryVisibility.historyVisibilityStr
+ ).toContent()
+ )
+ }
+
+ // ensure that the state did synced down
+ testHelper.waitWithLatch { latch ->
+ testHelper.retryPeriodicallyWithLatch(latch) {
+ aliceRoomPOV.stateService().getStateEvent(EventType.STATE_ROOM_HISTORY_VISIBILITY, QueryStringValue.IsEmpty)?.content
+ ?.toModel()?.historyVisibility == nextRoomHistoryVisibility.historyVisibility
+ }
+ }
+
+ testHelper.waitWithLatch { latch ->
+ testHelper.retryPeriodicallyWithLatch(latch) {
+ val roomVisibility = aliceSession.getRoom(e2eRoomID)!!
+ .stateService()
+ .getStateEvent(EventType.STATE_ROOM_HISTORY_VISIBILITY, QueryStringValue.IsEmpty)
+ ?.content
+ ?.toModel()
+ Log.v("#E2E TEST ROTATION", "Room visibility changed from: ${initRoomHistoryVisibility.name} to: ${roomVisibility?.historyVisibility?.name}")
+ roomVisibility?.historyVisibility == nextRoomHistoryVisibility.historyVisibility
+ }
+ }
+
+ var aliceThirdMessageSessionId: String? = null
+ sendMessageInRoom(aliceRoomPOV, "Message after visibility change", testHelper)?.let { thirdMessage ->
+ testHelper.waitWithLatch { latch ->
+ testHelper.retryPeriodicallyWithLatch(latch) {
+ val timelineEvent = bobRoomPov
+ ?.timelineService()
+ ?.getTimelineEvent(thirdMessage)
+ (timelineEvent != null &&
+ timelineEvent.isEncrypted() &&
+ timelineEvent.root.getClearType() == EventType.MESSAGE).also {
+ if (it) {
+ aliceThirdMessageSessionId = timelineEvent?.root?.content?.get("session_id") as? String
+ }
+ }
+ }
+ }
+ }
+
+ when {
+ initRoomHistoryVisibility.shouldShareHistory() == nextRoomHistoryVisibility.historyVisibility?.shouldShareHistory() -> {
+ assertEquals("Session shouldn't have been rotated", secondAliceMessageSessionId, aliceThirdMessageSessionId)
+ Log.v("#E2E TEST ROTATION", "Rotation is not needed")
+ }
+ initRoomHistoryVisibility.shouldShareHistory() != nextRoomHistoryVisibility.historyVisibility!!.shouldShareHistory() -> {
+ assertNotEquals("Session should have been rotated", secondAliceMessageSessionId, aliceThirdMessageSessionId)
+ Log.v("#E2E TEST ROTATION", "Rotation is needed!")
+ }
+ }
+
+ cryptoTestData.cleanUp(testHelper)
+ }
+
+ private fun sendMessageInRoom(aliceRoomPOV: Room, text: String, testHelper: CommonTestHelper): String? {
+ return testHelper.sendTextMessage(aliceRoomPOV, text, 1).firstOrNull()?.eventId
+ }
+
+ private fun ensureMembersHaveJoined(aliceSession: Session, otherAccounts: List, e2eRoomID: String, testHelper: CommonTestHelper) {
+ testHelper.waitWithLatch { latch ->
+ testHelper.retryPeriodicallyWithLatch(latch) {
+ otherAccounts.map {
+ aliceSession.roomService().getRoomMember(it.myUserId, e2eRoomID)?.membership
+ }.all {
+ it == Membership.JOIN
+ }
+ }
+ }
+ }
+
+ private fun waitForAndAcceptInviteInRoom(otherSession: Session, e2eRoomID: String, testHelper: CommonTestHelper) {
+ testHelper.waitWithLatch { latch ->
+ testHelper.retryPeriodicallyWithLatch(latch) {
+ val roomSummary = otherSession.roomService().getRoomSummary(e2eRoomID)
+ (roomSummary != null && roomSummary.membership == Membership.INVITE).also {
+ if (it) {
+ Log.v("#E2E TEST", "${otherSession.myUserId} can see the invite from alice")
+ }
+ }
+ }
+ }
+
+ testHelper.runBlockingTest(60_000) {
+ Log.v("#E2E TEST", "${otherSession.myUserId} tries to join room $e2eRoomID")
+ try {
+ otherSession.roomService().joinRoom(e2eRoomID)
+ } catch (ex: JoinRoomFailure.JoinedWithTimeout) {
+ // it's ok we will wait after
+ }
+ }
+
+ Log.v("#E2E TEST", "${otherSession.myUserId} waiting for join echo ...")
+ testHelper.waitWithLatch {
+ testHelper.retryPeriodicallyWithLatch(it) {
+ val roomSummary = otherSession.roomService().getRoomSummary(e2eRoomID)
+ roomSummary != null && roomSummary.membership == Membership.JOIN
+ }
+ }
+ }
+}
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 e37ae5be86..e8e7b1d708 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
@@ -72,7 +72,7 @@ class PreShareKeysTest : InstrumentedTest {
assertNotNull("Bob should have received and decrypted a room key event from alice", bobInboundForAlice)
assertEquals("Wrong room", e2eRoomID, bobInboundForAlice!!.roomId)
- val megolmSessionId = bobInboundForAlice.olmInboundGroupSession!!.sessionIdentifier()
+ val megolmSessionId = bobInboundForAlice.session.sessionIdentifier()
assertEquals("Wrong session", aliceOutboundSessionInRoom, megolmSessionId)
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 e8a474a54a..5fe7376184 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/UnwedgingTest.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/UnwedgingTest.kt
@@ -21,7 +21,6 @@ import org.amshove.kluent.shouldBe
import org.junit.Assert
import org.junit.Before
import org.junit.FixMethodOrder
-import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -60,7 +59,6 @@ import kotlin.coroutines.resume
*/
@RunWith(AndroidJUnit4::class)
@FixMethodOrder(MethodSorters.JVM)
-@Ignore
class UnwedgingTest : InstrumentedTest {
private lateinit var messagesReceivedByBob: List
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 994a055e5a..7bb53e139c 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
@@ -424,7 +424,7 @@ class KeyShareTests : InstrumentedTest {
// /!\ Stop initial alice session syncing so that it can't reply
aliceSession.cryptoService().enableKeyGossiping(false)
- aliceSession.stopSync()
+ aliceSession.syncService().stopSync()
// Let's now try to request
aliceNewSession.cryptoService().reRequestRoomKeyForEvent(sentEvents.first().root)
@@ -447,7 +447,7 @@ class KeyShareTests : InstrumentedTest {
// let's wake up alice
aliceSession.cryptoService().enableKeyGossiping(true)
- aliceSession.startSync(true)
+ aliceSession.syncService().startSync(true)
// We should now get a reply from first session
commonTestHelper.waitWithLatch { latch ->
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/gossiping/WithHeldTests.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/gossiping/WithHeldTests.kt
index ae420a09b3..0aac4297e4 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/gossiping/WithHeldTests.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/gossiping/WithHeldTests.kt
@@ -21,7 +21,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
import org.junit.Assert
import org.junit.FixMethodOrder
-import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -47,7 +46,6 @@ import org.matrix.android.sdk.mustFail
@RunWith(AndroidJUnit4::class)
@FixMethodOrder(MethodSorters.JVM)
@LargeTest
-@Ignore
class WithHeldTests : InstrumentedTest {
@get:Rule val rule = RetryTestRule(3)
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupScenarioData.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupScenarioData.kt
index 45fdb9e1e3..cf201611a0 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupScenarioData.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupScenarioData.kt
@@ -19,14 +19,14 @@ package org.matrix.android.sdk.internal.crypto.keysbackup
import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.common.CommonTestHelper
import org.matrix.android.sdk.common.CryptoTestData
-import org.matrix.android.sdk.internal.crypto.model.OlmInboundGroupSessionWrapper2
+import org.matrix.android.sdk.internal.crypto.model.MXInboundMegolmSessionWrapper
/**
* Data class to store result of [KeysBackupTestHelper.createKeysBackupScenarioWithPassword]
*/
internal data class KeysBackupScenarioData(
val cryptoTestData: CryptoTestData,
- val aliceKeys: List,
+ val aliceKeys: List,
val prepareKeysBackupDataResult: PrepareKeysBackupDataResult,
val aliceSession2: Session
) {
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 fb498e0de5..2439119f01 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupTest.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupTest.kt
@@ -24,7 +24,6 @@ import org.junit.Assert.assertNotNull
import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue
import org.junit.FixMethodOrder
-import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -56,7 +55,6 @@ import java.util.concurrent.CountDownLatch
@RunWith(AndroidJUnit4::class)
@FixMethodOrder(MethodSorters.JVM)
@LargeTest
-@Ignore
class KeysBackupTest : InstrumentedTest {
@get:Rule val rule = RetryTestRule(3)
@@ -301,7 +299,7 @@ class KeysBackupTest : InstrumentedTest {
val keyBackupCreationInfo = keysBackupTestHelper.prepareAndCreateKeysBackupData(keysBackup).megolmBackupCreationInfo
// - Check encryptGroupSession() returns stg
- val keyBackupData = keysBackup.encryptGroupSession(session)
+ val keyBackupData = testHelper.runBlockingTest { keysBackup.encryptGroupSession(session) }
assertNotNull(keyBackupData)
assertNotNull(keyBackupData!!.sessionData)
@@ -312,7 +310,7 @@ class KeysBackupTest : InstrumentedTest {
val sessionData = keysBackup
.decryptKeyBackupData(
keyBackupData,
- session.olmInboundGroupSession!!.sessionIdentifier(),
+ session.safeSessionId!!,
cryptoTestData.roomId,
decryption!!
)
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupTestHelper.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupTestHelper.kt
index 38f94c5103..2cc2b506b9 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupTestHelper.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupTestHelper.kt
@@ -187,7 +187,7 @@ internal class KeysBackupTestHelper(
// - Alice must have the same keys on both devices
for (aliceKey1 in testData.aliceKeys) {
val aliceKey2 = (testData.aliceSession2.cryptoService().keysBackupService() as DefaultKeysBackupService).store
- .getInboundGroupSession(aliceKey1.olmInboundGroupSession!!.sessionIdentifier(), aliceKey1.senderKey!!)
+ .getInboundGroupSession(aliceKey1.safeSessionId!!, aliceKey1.senderKey!!)
Assert.assertNotNull(aliceKey2)
assertKeysEquals(aliceKey1.exportKeys(), aliceKey2!!.exportKeys())
}
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/SASTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/SASTest.kt
index d524774a35..c2e74abc59 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/SASTest.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/SASTest.kt
@@ -415,7 +415,7 @@ class SASTest : InstrumentedTest {
OutgoingSasVerificationTransaction.UxState.SHOW_SAS -> {
aliceSASLatch.countDown()
}
- else -> Unit
+ else -> Unit
}
}
}
@@ -429,7 +429,7 @@ class SASTest : InstrumentedTest {
IncomingSasVerificationTransaction.UxState.SHOW_ACCEPT -> {
tx.performAccept()
}
- else -> Unit
+ else -> Unit
}
if (uxState === IncomingSasVerificationTransaction.UxState.SHOW_SAS) {
bobSASLatch.countDown()
@@ -479,7 +479,7 @@ class SASTest : InstrumentedTest {
aliceSASLatch.countDown()
}
}
- else -> Unit
+ else -> Unit
}
}
}
@@ -499,16 +499,16 @@ class SASTest : InstrumentedTest {
tx.performAccept()
}
}
- IncomingSasVerificationTransaction.UxState.SHOW_SAS -> {
+ IncomingSasVerificationTransaction.UxState.SHOW_SAS -> {
if (matchOnce) {
matchOnce = false
tx.userHasVerifiedShortCode()
}
}
- IncomingSasVerificationTransaction.UxState.VERIFIED -> {
+ IncomingSasVerificationTransaction.UxState.VERIFIED -> {
bobSASLatch.countDown()
}
- else -> Unit
+ else -> Unit
}
}
}
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/session/room/send/TestPermalinkService.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/session/room/send/TestPermalinkService.kt
index 2f9a5e0a73..3a267ec694 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/session/room/send/TestPermalinkService.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/session/room/send/TestPermalinkService.kt
@@ -44,7 +44,7 @@ class TestPermalinkService : PermalinkService {
override fun createMentionSpanTemplate(type: PermalinkService.SpanTemplateType, forceMatrixTo: Boolean): String {
return when (type) {
- HTML -> "%2\$s"
+ HTML -> "%2\$s"
MARKDOWN -> "[%2\$s](https://matrix.to/#/%1\$s)"
}
}
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/threads/ThreadMessagingTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/threads/ThreadMessagingTest.kt
index 1ffcc2a3e6..45bd38870d 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
@@ -83,7 +83,7 @@ class ThreadMessagingTest : InstrumentedTest {
val timeline = aliceRoom.timelineService().createTimeline(null, TimelineSettings(30))
timeline.start()
- aliceSession.startSync(true)
+ aliceSession.syncService().startSync(true)
run {
val lock = CountDownLatch(1)
val eventsListener = commonTestHelper.createEventListener(lock) { snapshot ->
@@ -97,7 +97,7 @@ class ThreadMessagingTest : InstrumentedTest {
timeline.addListener(eventsListener)
commonTestHelper.await(lock, 600_000)
}
- aliceSession.stopSync()
+ aliceSession.syncService().stopSync()
}
@Test
@@ -144,7 +144,7 @@ class ThreadMessagingTest : InstrumentedTest {
val timeline = aliceRoom.timelineService().createTimeline(null, TimelineSettings(30))
timeline.start()
- aliceSession.startSync(true)
+ aliceSession.syncService().startSync(true)
run {
val lock = CountDownLatch(1)
val eventsListener = commonTestHelper.createEventListener(lock) { snapshot ->
@@ -156,9 +156,9 @@ class ThreadMessagingTest : InstrumentedTest {
timeline.addListener(eventsListener)
commonTestHelper.await(lock, 600_000)
}
- aliceSession.stopSync()
+ aliceSession.syncService().stopSync()
- bobSession.startSync(true)
+ bobSession.syncService().startSync(true)
run {
val lock = CountDownLatch(1)
val eventsListener = commonTestHelper.createEventListener(lock) { snapshot ->
@@ -170,7 +170,7 @@ class ThreadMessagingTest : InstrumentedTest {
timeline.addListener(eventsListener)
commonTestHelper.await(lock, 600_000)
}
- bobSession.stopSync()
+ bobSession.syncService().stopSync()
}
@Test
@@ -217,7 +217,7 @@ class ThreadMessagingTest : InstrumentedTest {
val timeline = aliceRoom.timelineService().createTimeline(null, TimelineSettings(30))
timeline.start()
- aliceSession.startSync(true)
+ aliceSession.syncService().startSync(true)
run {
val lock = CountDownLatch(1)
val eventsListener = commonTestHelper.createEventListener(lock) { snapshot ->
@@ -233,7 +233,7 @@ class ThreadMessagingTest : InstrumentedTest {
timeline.addListener(eventsListener)
commonTestHelper.await(lock, 600_000)
}
- aliceSession.stopSync()
+ aliceSession.syncService().stopSync()
}
@Test
@@ -314,7 +314,7 @@ class ThreadMessagingTest : InstrumentedTest {
val timeline = aliceRoom.timelineService().createTimeline(null, TimelineSettings(30))
timeline.start()
- aliceSession.startSync(true)
+ aliceSession.syncService().startSync(true)
run {
val lock = CountDownLatch(1)
val eventsListener = commonTestHelper.createEventListener(lock) { snapshot ->
@@ -338,6 +338,6 @@ class ThreadMessagingTest : InstrumentedTest {
timeline.addListener(eventsListener)
commonTestHelper.await(lock, 600_000)
}
- aliceSession.stopSync()
+ aliceSession.syncService().stopSync()
}
}
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/ChunkEntityTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/ChunkEntityTest.kt
index 986d58741c..7b0d57abbc 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/ChunkEntityTest.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/ChunkEntityTest.kt
@@ -22,7 +22,6 @@ import io.realm.Realm
import io.realm.RealmConfiguration
import io.realm.kotlin.createObject
import org.amshove.kluent.shouldBeEqualTo
-import org.amshove.kluent.shouldBeTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -30,13 +29,11 @@ import org.matrix.android.sdk.InstrumentedTest
import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.room.send.SendState
import org.matrix.android.sdk.internal.database.helper.addTimelineEvent
-import org.matrix.android.sdk.internal.database.helper.merge
import org.matrix.android.sdk.internal.database.mapper.toEntity
import org.matrix.android.sdk.internal.database.model.ChunkEntity
import org.matrix.android.sdk.internal.database.model.SessionRealmModule
import org.matrix.android.sdk.internal.session.room.timeline.PaginationDirection
import org.matrix.android.sdk.internal.util.time.DefaultClock
-import org.matrix.android.sdk.session.room.timeline.RoomDataHelper.createFakeListOfEvents
import org.matrix.android.sdk.session.room.timeline.RoomDataHelper.createFakeMessageEvent
@RunWith(AndroidJUnit4::class)
@@ -97,63 +94,6 @@ internal class ChunkEntityTest : InstrumentedTest {
}
}
- @Test
- fun merge_shouldAddEvents_whenMergingBackward() {
- monarchy.runTransactionSync { realm ->
- val chunk1: ChunkEntity = realm.createObject()
- val chunk2: ChunkEntity = realm.createObject()
- chunk1.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
- chunk2.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
- chunk1.merge(ROOM_ID, chunk2, PaginationDirection.BACKWARDS)
- chunk1.timelineEvents.size shouldBeEqualTo 60
- }
- }
-
- @Test
- fun merge_shouldAddOnlyDifferentEvents_whenMergingBackward() {
- monarchy.runTransactionSync { realm ->
- val chunk1: ChunkEntity = realm.createObject()
- val chunk2: ChunkEntity = realm.createObject()
- val eventsForChunk1 = createFakeListOfEvents(30)
- val eventsForChunk2 = eventsForChunk1 + createFakeListOfEvents(10)
- chunk1.isLastForward = true
- chunk2.isLastForward = false
- chunk1.addAll(ROOM_ID, eventsForChunk1, PaginationDirection.FORWARDS)
- chunk2.addAll(ROOM_ID, eventsForChunk2, PaginationDirection.BACKWARDS)
- chunk1.merge(ROOM_ID, chunk2, PaginationDirection.BACKWARDS)
- chunk1.timelineEvents.size shouldBeEqualTo 40
- chunk1.isLastForward.shouldBeTrue()
- }
- }
-
- @Test
- fun merge_shouldPrevTokenMerged_whenMergingForwards() {
- monarchy.runTransactionSync { realm ->
- val chunk1: ChunkEntity = realm.createObject()
- val chunk2: ChunkEntity = realm.createObject()
- val prevToken = "prev_token"
- chunk1.prevToken = prevToken
- chunk1.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
- chunk2.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
- chunk1.merge(ROOM_ID, chunk2, PaginationDirection.FORWARDS)
- chunk1.prevToken shouldBeEqualTo prevToken
- }
- }
-
- @Test
- fun merge_shouldNextTokenMerged_whenMergingBackwards() {
- monarchy.runTransactionSync { realm ->
- val chunk1: ChunkEntity = realm.createObject()
- val chunk2: ChunkEntity = realm.createObject()
- val nextToken = "next_token"
- chunk1.nextToken = nextToken
- chunk1.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
- chunk2.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
- chunk1.merge(ROOM_ID, chunk2, PaginationDirection.BACKWARDS)
- chunk1.nextToken shouldBeEqualTo nextToken
- }
- }
-
private fun ChunkEntity.addAll(
roomId: String,
events: List,
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 2b72ecc52a..a37d2ce015 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
@@ -57,7 +57,7 @@ class PollAggregationTest : InstrumentedTest {
// Bob creates a poll
roomFromBobPOV.sendService().sendPoll(PollType.DISCLOSED, pollQuestion, pollOptions)
- aliceSession.startSync(true)
+ aliceSession.syncService().startSync(true)
val aliceTimeline = roomFromAlicePOV.timelineService().createTimeline(null, TimelineSettings(30))
aliceTimeline.start()
@@ -77,7 +77,7 @@ class PollAggregationTest : InstrumentedTest {
}
when (lock.count.toInt()) {
- TOTAL_TEST_COUNT -> {
+ TOTAL_TEST_COUNT -> {
// Poll has just been created.
testInitialPollConditions(pollContent, pollSummary)
lock.countDown()
@@ -119,7 +119,7 @@ class PollAggregationTest : InstrumentedTest {
testEndedPoll(pollSummary)
lock.countDown()
}
- else -> {
+ else -> {
fail("Lock count ${lock.count} didn't handled.")
}
}
@@ -133,7 +133,7 @@ class PollAggregationTest : InstrumentedTest {
aliceTimeline.removeAllListeners()
- aliceSession.stopSync()
+ aliceSession.syncService().stopSync()
aliceTimeline.dispose()
}
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 3dd3f5fa2a..2e5c69b048 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
@@ -22,6 +22,7 @@ import org.amshove.kluent.internal.assertEquals
import org.amshove.kluent.shouldBeFalse
import org.amshove.kluent.shouldBeTrue
import org.junit.FixMethodOrder
+import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@@ -52,6 +53,7 @@ class TimelineForwardPaginationTest : InstrumentedTest {
* This test ensure that if we click to permalink, we will be able to go back to the live
*/
@Test
+ @Ignore("Ignoring this test until it's fixed since it blocks the CI.")
fun forwardPaginationTest() = runCryptoTest(context()) { cryptoTestHelper, commonTestHelper ->
val numberOfMessagesToSend = 90
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceInARoom(false)
@@ -163,6 +165,8 @@ class TimelineForwardPaginationTest : InstrumentedTest {
// Ask for a forward pagination
val snapshot = runBlocking {
aliceTimeline.awaitPaginate(Timeline.Direction.FORWARDS, 50)
+ // We should paginate one more time to check we are at the end now that chunks are not merged.
+ aliceTimeline.awaitPaginate(Timeline.Direction.FORWARDS, 50)
}
// 7 for room creation item (backward pagination),and numberOfMessagesToSend (all the message of the room)
snapshot.size == 7 + numberOfMessagesToSend &&
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 3ff4572add..7c1a097b24 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelinePreviousLastForwardTest.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelinePreviousLastForwardTest.kt
@@ -20,6 +20,7 @@ import androidx.test.filters.LargeTest
import org.amshove.kluent.shouldBeFalse
import org.amshove.kluent.shouldBeTrue
import org.junit.FixMethodOrder
+import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@@ -39,6 +40,7 @@ import java.util.concurrent.CountDownLatch
@RunWith(JUnit4::class)
@FixMethodOrder(MethodSorters.JVM)
+@Ignore("This test will be ignored until it is fixed")
@LargeTest
class TimelinePreviousLastForwardTest : InstrumentedTest {
@@ -88,7 +90,7 @@ class TimelinePreviousLastForwardTest : InstrumentedTest {
}
// Bob stop to sync
- bobSession.stopSync()
+ bobSession.syncService().stopSync()
val firstMessage = "First messages from Alice"
// Alice sends 30 messages
@@ -101,7 +103,7 @@ class TimelinePreviousLastForwardTest : InstrumentedTest {
.eventId
// Bob start to sync
- bobSession.startSync(true)
+ bobSession.syncService().startSync(true)
run {
val lock = CountDownLatch(1)
@@ -125,7 +127,7 @@ class TimelinePreviousLastForwardTest : InstrumentedTest {
}
// Bob stop to sync
- bobSession.stopSync()
+ bobSession.syncService().stopSync()
val secondMessage = "Second messages from Alice"
// Alice sends again 30 messages
@@ -136,7 +138,7 @@ class TimelinePreviousLastForwardTest : InstrumentedTest {
)
// Bob start to sync
- bobSession.startSync(true)
+ bobSession.syncService().startSync(true)
run {
val lock = CountDownLatch(1)
@@ -229,6 +231,7 @@ class TimelinePreviousLastForwardTest : InstrumentedTest {
bobTimeline.addListener(eventsListener)
+ bobTimeline.paginate(Timeline.Direction.FORWARDS, 50)
bobTimeline.paginate(Timeline.Direction.FORWARDS, 50)
commonTestHelper.await(lock)
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 87f404b0f1..27ea0e1c3c 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
@@ -71,7 +71,7 @@ class TimelineWithManyMembersTest : InstrumentedTest {
val timelineForCurrentMember = roomForCurrentMember.timelineService().createTimeline(null, TimelineSettings(30))
timelineForCurrentMember.start()
- session.startSync(true)
+ session.syncService().startSync(true)
run {
val lock = CountDownLatch(1)
@@ -92,7 +92,7 @@ class TimelineWithManyMembersTest : InstrumentedTest {
timelineForCurrentMember.addListener(eventsListener)
commonTestHelper.await(lock, 600_000)
}
- session.stopSync()
+ session.syncService().stopSync()
}
}
}
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/space/SpaceCreationTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/space/SpaceCreationTest.kt
index 0cc0ef57c4..2cd579df24 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
@@ -28,6 +28,7 @@ import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import org.junit.runners.MethodSorters
import org.matrix.android.sdk.InstrumentedTest
+import org.matrix.android.sdk.api.query.QueryStringValue
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
@@ -55,45 +56,53 @@ class SpaceCreationTest : InstrumentedTest {
val roomName = "My Space"
val topic = "A public space for test"
var spaceId: String = ""
- commonTestHelper.waitWithLatch {
+ commonTestHelper.runBlockingTest {
spaceId = session.spaceService().createSpace(roomName, topic, null, true)
- // wait a bit to let the summary update it self :/
- it.countDown()
}
- Thread.sleep(4_000)
- val syncedSpace = session.spaceService().getSpace(spaceId)
commonTestHelper.waitWithLatch {
commonTestHelper.retryPeriodicallyWithLatch(it) {
- syncedSpace?.asRoom()?.roomSummary()?.name != null
+ session.spaceService().getSpace(spaceId)?.asRoom()?.roomSummary()?.name != null
}
}
+
+ val syncedSpace = session.spaceService().getSpace(spaceId)
assertEquals("Room name should be set", roomName, syncedSpace?.asRoom()?.roomSummary()?.name)
assertEquals("Room topic should be set", topic, syncedSpace?.asRoom()?.roomSummary()?.topic)
// assertEquals(topic, syncedSpace.asRoom().roomSummary()?., "Room topic should be set")
assertNotNull("Space should be found by Id", syncedSpace)
- val creationEvent = syncedSpace!!.asRoom().getStateEvent(EventType.STATE_ROOM_CREATE)
- val createContent = creationEvent?.content.toModel()
+ val createContent = syncedSpace!!.asRoom()
+ .getStateEvent(EventType.STATE_ROOM_CREATE, QueryStringValue.IsEmpty)
+ ?.content
+ ?.toModel()
assertEquals("Room type should be space", RoomType.SPACE, createContent?.type)
var powerLevelsContent: PowerLevelsContent? = null
commonTestHelper.waitWithLatch { latch ->
commonTestHelper.retryPeriodicallyWithLatch(latch) {
- val toModel = syncedSpace.asRoom().getStateEvent(EventType.STATE_ROOM_POWER_LEVELS)?.content.toModel()
- powerLevelsContent = toModel
- toModel != null
+ powerLevelsContent = syncedSpace.asRoom()
+ .getStateEvent(EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.IsEmpty)
+ ?.content
+ ?.toModel()
+ powerLevelsContent != null
}
}
assertEquals("Space-rooms should be created with a power level for events_default of 100", 100, powerLevelsContent?.eventsDefault)
- val guestAccess = syncedSpace.asRoom().getStateEvent(EventType.STATE_ROOM_GUEST_ACCESS)?.content
- ?.toModel()?.guestAccess
+ val guestAccess = syncedSpace.asRoom()
+ .getStateEvent(EventType.STATE_ROOM_GUEST_ACCESS, QueryStringValue.IsEmpty)
+ ?.content
+ ?.toModel()
+ ?.guestAccess
assertEquals("Public space room should be peekable by guest", GuestAccess.CanJoin, guestAccess)
- val historyVisibility = syncedSpace.asRoom().getStateEvent(EventType.STATE_ROOM_HISTORY_VISIBILITY)?.content
- ?.toModel()?.historyVisibility
+ val historyVisibility = syncedSpace.asRoom()
+ .getStateEvent(EventType.STATE_ROOM_HISTORY_VISIBILITY, QueryStringValue.IsEmpty)
+ ?.content
+ ?.toModel()
+ ?.historyVisibility
assertEquals("Public space room should be world readable", RoomHistoryVisibility.WORLD_READABLE, historyVisibility)
}
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 5396251438..18645fd6d9 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
@@ -20,7 +20,6 @@ import android.util.Log
import androidx.lifecycle.Observer
import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertEquals
-import org.junit.Assert.assertNotNull
import org.junit.Assert.assertTrue
import org.junit.FixMethodOrder
import org.junit.Ignore
@@ -62,47 +61,40 @@ class SpaceHierarchyTest : InstrumentedTest {
val spaceName = "My Space"
val topic = "A public space for test"
var spaceId = ""
- commonTestHelper.waitWithLatch {
+ commonTestHelper.runBlockingTest {
spaceId = session.spaceService().createSpace(spaceName, topic, null, true)
- it.countDown()
}
val syncedSpace = session.spaceService().getSpace(spaceId)
var roomId = ""
- commonTestHelper.waitWithLatch {
+ commonTestHelper.runBlockingTest {
roomId = session.roomService().createRoom(CreateRoomParams().apply { name = "General" })
- it.countDown()
}
val viaServers = listOf(session.sessionParams.homeServerHost ?: "")
- commonTestHelper.waitWithLatch {
+ commonTestHelper.runBlockingTest {
syncedSpace!!.addChildren(roomId, viaServers, null, true)
- it.countDown()
}
- commonTestHelper.waitWithLatch {
+ commonTestHelper.runBlockingTest {
session.spaceService().setSpaceParent(roomId, spaceId, true, viaServers)
- it.countDown()
}
- Thread.sleep(9000)
-
- val parents = session.getRoom(roomId)?.roomSummary()?.spaceParents
- val canonicalParents = session.getRoom(roomId)?.roomSummary()?.spaceParents?.filter { it.canonical == true }
-
- parents?.forEach {
- Log.d("## TEST", "parent : $it")
+ commonTestHelper.waitWithLatch { latch ->
+ commonTestHelper.retryPeriodicallyWithLatch(latch) {
+ val parents = session.getRoom(roomId)?.roomSummary()?.spaceParents
+ val canonicalParents = session.getRoom(roomId)?.roomSummary()?.spaceParents?.filter { it.canonical == true }
+ parents?.forEach {
+ Log.d("## TEST", "parent : $it")
+ }
+ parents?.size == 1 &&
+ parents.first().roomSummary?.name == spaceName &&
+ canonicalParents?.size == 1 &&
+ canonicalParents.first().roomSummary?.name == spaceName
+ }
}
-
- assertNotNull(parents)
- assertEquals(1, parents!!.size)
- assertEquals(spaceName, parents.first().roomSummary?.name)
-
- assertNotNull(canonicalParents)
- assertEquals(1, canonicalParents!!.size)
- assertEquals(spaceName, canonicalParents.first().roomSummary?.name)
}
// @Test
@@ -173,52 +165,55 @@ class SpaceHierarchyTest : InstrumentedTest {
// }
@Test
- fun testFilteringBySpace() = CommonTestHelper.runSessionTest(context()) { commonTestHelper ->
+ fun testFilteringBySpace() = runSessionTest(context()) { commonTestHelper ->
val session = commonTestHelper.createAccount("John", SessionTestParams(true))
val spaceAInfo = createPublicSpace(
- session, "SpaceA", listOf(
- Triple("A1", true /*auto-join*/, true/*canonical*/),
- Triple("A2", true, true)
- )
+ commonTestHelper,
+ session, "SpaceA",
+ listOf(
+ Triple("A1", true /*auto-join*/, true/*canonical*/),
+ Triple("A2", true, true)
+ )
)
/* val spaceBInfo = */ createPublicSpace(
- session, "SpaceB", listOf(
- Triple("B1", true /*auto-join*/, true/*canonical*/),
- Triple("B2", true, true),
- Triple("B3", true, true)
- )
+ commonTestHelper,
+ session, "SpaceB",
+ listOf(
+ Triple("B1", true /*auto-join*/, true/*canonical*/),
+ Triple("B2", true, true),
+ Triple("B3", true, true)
+ )
)
val spaceCInfo = createPublicSpace(
- session, "SpaceC", listOf(
- Triple("C1", true /*auto-join*/, true/*canonical*/),
- Triple("C2", true, true)
- )
+ commonTestHelper,
+ session, "SpaceC",
+ listOf(
+ Triple("C1", true /*auto-join*/, true/*canonical*/),
+ Triple("C2", true, true)
+ )
)
// add C as a subspace of A
val spaceA = session.spaceService().getSpace(spaceAInfo.spaceId)
val viaServers = listOf(session.sessionParams.homeServerHost ?: "")
- commonTestHelper.waitWithLatch {
+ commonTestHelper.runBlockingTest {
spaceA!!.addChildren(spaceCInfo.spaceId, viaServers, null, true)
session.spaceService().setSpaceParent(spaceCInfo.spaceId, spaceAInfo.spaceId, true, viaServers)
- it.countDown()
}
// Create orphan rooms
var orphan1 = ""
- commonTestHelper.waitWithLatch {
+ commonTestHelper.runBlockingTest {
orphan1 = session.roomService().createRoom(CreateRoomParams().apply { name = "O1" })
- it.countDown()
}
var orphan2 = ""
- commonTestHelper.waitWithLatch {
+ commonTestHelper.runBlockingTest {
orphan2 = session.roomService().createRoom(CreateRoomParams().apply { name = "O2" })
- it.countDown()
}
val allRooms = session.roomService().getRoomSummaries(roomSummaryQueryParams { excludeType = listOf(RoomType.SPACE) })
@@ -240,10 +235,9 @@ class SpaceHierarchyTest : InstrumentedTest {
assertTrue("A1 should be a grand child of A", aChildren.any { it.name == "C2" })
// Add a non canonical child and check that it does not appear as orphan
- commonTestHelper.waitWithLatch {
+ commonTestHelper.runBlockingTest {
val a3 = session.roomService().createRoom(CreateRoomParams().apply { name = "A3" })
spaceA!!.addChildren(a3, viaServers, null, false)
- it.countDown()
}
Thread.sleep(6_000)
@@ -255,37 +249,39 @@ class SpaceHierarchyTest : InstrumentedTest {
@Test
@Ignore("This test will be ignored until it is fixed")
- fun testBreakCycle() = CommonTestHelper.runSessionTest(context()) { commonTestHelper ->
+ fun testBreakCycle() = runSessionTest(context()) { commonTestHelper ->
val session = commonTestHelper.createAccount("John", SessionTestParams(true))
val spaceAInfo = createPublicSpace(
- session, "SpaceA", listOf(
- Triple("A1", true /*auto-join*/, true/*canonical*/),
- Triple("A2", true, true)
- )
+ commonTestHelper,
+ session, "SpaceA",
+ listOf(
+ Triple("A1", true /*auto-join*/, true/*canonical*/),
+ Triple("A2", true, true)
+ )
)
val spaceCInfo = createPublicSpace(
- session, "SpaceC", listOf(
- Triple("C1", true /*auto-join*/, true/*canonical*/),
- Triple("C2", true, true)
- )
+ commonTestHelper,
+ session, "SpaceC",
+ listOf(
+ Triple("C1", true /*auto-join*/, true/*canonical*/),
+ Triple("C2", true, true)
+ )
)
// add C as a subspace of A
val spaceA = session.spaceService().getSpace(spaceAInfo.spaceId)
val viaServers = listOf(session.sessionParams.homeServerHost ?: "")
- commonTestHelper.waitWithLatch {
+ commonTestHelper.runBlockingTest {
spaceA!!.addChildren(spaceCInfo.spaceId, viaServers, null, true)
session.spaceService().setSpaceParent(spaceCInfo.spaceId, spaceAInfo.spaceId, true, viaServers)
- it.countDown()
}
// add back A as subspace of C
- commonTestHelper.waitWithLatch {
+ commonTestHelper.runBlockingTest {
val spaceC = session.spaceService().getSpace(spaceCInfo.spaceId)
spaceC!!.addChildren(spaceAInfo.spaceId, viaServers, null, true)
- it.countDown()
}
// A -> C -> A
@@ -300,37 +296,46 @@ class SpaceHierarchyTest : InstrumentedTest {
}
@Test
- fun testLiveFlatChildren() = CommonTestHelper.runSessionTest(context()) { commonTestHelper ->
+ fun testLiveFlatChildren() = runSessionTest(context()) { commonTestHelper ->
val session = commonTestHelper.createAccount("John", SessionTestParams(true))
val spaceAInfo = createPublicSpace(
- session, "SpaceA", listOf(
- Triple("A1", true /*auto-join*/, true/*canonical*/),
- Triple("A2", true, true)
- )
+ commonTestHelper,
+ session,
+ "SpaceA",
+ listOf(
+ Triple("A1", true /*auto-join*/, true/*canonical*/),
+ Triple("A2", true, true)
+ )
)
val spaceBInfo = createPublicSpace(
- session, "SpaceB", listOf(
- Triple("B1", true /*auto-join*/, true/*canonical*/),
- Triple("B2", true, true),
- Triple("B3", true, true)
- )
+ commonTestHelper,
+ session,
+ "SpaceB",
+ listOf(
+ Triple("B1", true /*auto-join*/, true/*canonical*/),
+ Triple("B2", true, true),
+ Triple("B3", true, true)
+ )
)
// add B as a subspace of A
val spaceA = session.spaceService().getSpace(spaceAInfo.spaceId)
val viaServers = listOf(session.sessionParams.homeServerHost ?: "")
- runBlocking {
+ commonTestHelper.runBlockingTest {
spaceA!!.addChildren(spaceBInfo.spaceId, viaServers, null, true)
session.spaceService().setSpaceParent(spaceBInfo.spaceId, spaceAInfo.spaceId, true, viaServers)
}
val spaceCInfo = createPublicSpace(
- session, "SpaceC", listOf(
- Triple("C1", true /*auto-join*/, true/*canonical*/),
- Triple("C2", true, true)
- )
+ commonTestHelper,
+ session,
+ "SpaceC",
+ listOf(
+ Triple("C1", true /*auto-join*/, true/*canonical*/),
+ Triple("C2", true, true)
+ )
)
commonTestHelper.waitWithLatch { latch ->
@@ -348,13 +353,13 @@ class SpaceHierarchyTest : InstrumentedTest {
}
}
+ flatAChildren.observeForever(childObserver)
+
// add C as subspace of B
val spaceB = session.spaceService().getSpace(spaceBInfo.spaceId)
spaceB!!.addChildren(spaceCInfo.spaceId, viaServers, null, true)
// C1 and C2 should be in flatten child of A now
-
- flatAChildren.observeForever(childObserver)
}
// Test part one of the rooms
@@ -374,10 +379,10 @@ class SpaceHierarchyTest : InstrumentedTest {
}
}
- // part from b room
- session.roomService().leaveRoom(bRoomId)
// The room should have disapear from flat children
flatAChildren.observeForever(childObserver)
+ // part from b room
+ session.roomService().leaveRoom(bRoomId)
}
commonTestHelper.signOutAndClose(session)
}
@@ -388,6 +393,7 @@ class SpaceHierarchyTest : InstrumentedTest {
)
private fun createPublicSpace(
+ commonTestHelper: CommonTestHelper,
session: Session,
spaceName: String,
childInfo: List>
@@ -395,29 +401,27 @@ class SpaceHierarchyTest : InstrumentedTest {
): TestSpaceCreationResult {
var spaceId = ""
var roomIds: List = emptyList()
- runSessionTest(context()) { commonTestHelper ->
- commonTestHelper.waitWithLatch { latch ->
- spaceId = session.spaceService().createSpace(spaceName, "Test Topic", null, true)
- val syncedSpace = session.spaceService().getSpace(spaceId)
- val viaServers = listOf(session.sessionParams.homeServerHost ?: "")
+ commonTestHelper.runBlockingTest {
+ spaceId = session.spaceService().createSpace(spaceName, "Test Topic", null, true)
+ val syncedSpace = session.spaceService().getSpace(spaceId)
+ val viaServers = listOf(session.sessionParams.homeServerHost ?: "")
- roomIds = childInfo.map { entry ->
- session.roomService().createRoom(CreateRoomParams().apply { name = entry.first })
+ roomIds = childInfo.map { entry ->
+ session.roomService().createRoom(CreateRoomParams().apply { name = entry.first })
+ }
+ roomIds.forEachIndexed { index, roomId ->
+ syncedSpace!!.addChildren(roomId, viaServers, null, childInfo[index].second)
+ val canonical = childInfo[index].third
+ if (canonical != null) {
+ session.spaceService().setSpaceParent(roomId, spaceId, canonical, viaServers)
}
- roomIds.forEachIndexed { index, roomId ->
- syncedSpace!!.addChildren(roomId, viaServers, null, childInfo[index].second)
- val canonical = childInfo[index].third
- if (canonical != null) {
- session.spaceService().setSpaceParent(roomId, spaceId, canonical, viaServers)
- }
- }
- latch.countDown()
}
}
return TestSpaceCreationResult(spaceId, roomIds)
}
private fun createPrivateSpace(
+ commonTestHelper: CommonTestHelper,
session: Session,
spaceName: String,
childInfo: List>
@@ -425,34 +429,31 @@ class SpaceHierarchyTest : InstrumentedTest {
): TestSpaceCreationResult {
var spaceId = ""
var roomIds: List = emptyList()
- runSessionTest(context()) { commonTestHelper ->
- commonTestHelper.waitWithLatch { latch ->
- spaceId = session.spaceService().createSpace(spaceName, "My Private Space", null, false)
- val syncedSpace = session.spaceService().getSpace(spaceId)
- val viaServers = listOf(session.sessionParams.homeServerHost ?: "")
- roomIds =
- childInfo.map { entry ->
- val homeServerCapabilities = session
- .homeServerCapabilitiesService()
- .getHomeServerCapabilities()
- session.roomService().createRoom(CreateRoomParams().apply {
- name = entry.first
- this.featurePreset = RestrictedRoomPreset(
- homeServerCapabilities,
- listOf(
- RoomJoinRulesAllowEntry.restrictedToRoom(spaceId)
- )
- )
- })
- }
- roomIds.forEachIndexed { index, roomId ->
- syncedSpace!!.addChildren(roomId, viaServers, null, childInfo[index].second)
- val canonical = childInfo[index].third
- if (canonical != null) {
- session.spaceService().setSpaceParent(roomId, spaceId, canonical, viaServers)
+ commonTestHelper.runBlockingTest {
+ spaceId = session.spaceService().createSpace(spaceName, "My Private Space", null, false)
+ val syncedSpace = session.spaceService().getSpace(spaceId)
+ val viaServers = listOf(session.sessionParams.homeServerHost ?: "")
+ roomIds =
+ childInfo.map { entry ->
+ val homeServerCapabilities = session
+ .homeServerCapabilitiesService()
+ .getHomeServerCapabilities()
+ session.roomService().createRoom(CreateRoomParams().apply {
+ name = entry.first
+ this.featurePreset = RestrictedRoomPreset(
+ homeServerCapabilities,
+ listOf(
+ RoomJoinRulesAllowEntry.restrictedToRoom(spaceId)
+ )
+ )
+ })
}
+ roomIds.forEachIndexed { index, roomId ->
+ syncedSpace!!.addChildren(roomId, viaServers, null, childInfo[index].second)
+ val canonical = childInfo[index].third
+ if (canonical != null) {
+ session.spaceService().setSpaceParent(roomId, spaceId, canonical, viaServers)
}
- latch.countDown()
}
}
return TestSpaceCreationResult(spaceId, roomIds)
@@ -463,25 +464,31 @@ class SpaceHierarchyTest : InstrumentedTest {
val session = commonTestHelper.createAccount("John", SessionTestParams(true))
/* val spaceAInfo = */ createPublicSpace(
- session, "SpaceA", listOf(
- Triple("A1", true /*auto-join*/, true/*canonical*/),
- Triple("A2", true, true)
- )
+ commonTestHelper,
+ session, "SpaceA",
+ listOf(
+ Triple("A1", true /*auto-join*/, true/*canonical*/),
+ Triple("A2", true, true)
+ )
)
val spaceBInfo = createPublicSpace(
- session, "SpaceB", listOf(
- Triple("B1", true /*auto-join*/, true/*canonical*/),
- Triple("B2", true, true),
- Triple("B3", true, true)
- )
+ commonTestHelper,
+ session, "SpaceB",
+ listOf(
+ Triple("B1", true /*auto-join*/, true/*canonical*/),
+ Triple("B2", true, true),
+ Triple("B3", true, true)
+ )
)
val spaceCInfo = createPublicSpace(
- session, "SpaceC", listOf(
- Triple("C1", true /*auto-join*/, true/*canonical*/),
- Triple("C2", true, true)
- )
+ commonTestHelper,
+ session, "SpaceC",
+ listOf(
+ Triple("C1", true /*auto-join*/, true/*canonical*/),
+ Triple("C2", true, true)
+ )
)
val viaServers = listOf(session.sessionParams.homeServerHost ?: "")
@@ -490,7 +497,6 @@ class SpaceHierarchyTest : InstrumentedTest {
runBlocking {
val spaceB = session.spaceService().getSpace(spaceBInfo.spaceId)
spaceB!!.addChildren(spaceCInfo.spaceId, viaServers, null, true)
- Thread.sleep(6_000)
}
// Thread.sleep(4_000)
@@ -501,11 +507,12 @@ class SpaceHierarchyTest : InstrumentedTest {
// + C
// + c1, c2
- val rootSpaces = commonTestHelper.runBlockingTest {
- session.spaceService().getRootSpaceSummaries()
+ commonTestHelper.waitWithLatch { latch ->
+ commonTestHelper.retryPeriodicallyWithLatch(latch) {
+ val rootSpaces = commonTestHelper.runBlockingTest { session.spaceService().getRootSpaceSummaries() }
+ rootSpaces.size == 2
+ }
}
-
- assertEquals("Unexpected number of root spaces ${rootSpaces.map { it.name }}", 2, rootSpaces.size)
}
@Test
@@ -514,10 +521,12 @@ class SpaceHierarchyTest : InstrumentedTest {
val bobSession = commonTestHelper.createAccount("Bib", SessionTestParams(true))
val spaceAInfo = createPrivateSpace(
- aliceSession, "Private Space A", listOf(
- Triple("General", true /*suggested*/, true/*canonical*/),
- Triple("Random", true, true)
- )
+ commonTestHelper,
+ aliceSession, "Private Space A",
+ listOf(
+ Triple("General", true /*suggested*/, true/*canonical*/),
+ Triple("Random", true, true)
+ )
)
commonTestHelper.runBlockingTest {
@@ -529,10 +538,9 @@ class SpaceHierarchyTest : InstrumentedTest {
}
var bobRoomId = ""
- commonTestHelper.waitWithLatch {
+ commonTestHelper.runBlockingTest {
bobRoomId = bobSession.roomService().createRoom(CreateRoomParams().apply { name = "A Bob Room" })
bobSession.getRoom(bobRoomId)!!.membershipService().invite(aliceSession.myUserId)
- it.countDown()
}
commonTestHelper.runBlockingTest {
@@ -545,9 +553,8 @@ class SpaceHierarchyTest : InstrumentedTest {
}
}
- commonTestHelper.waitWithLatch {
+ commonTestHelper.runBlockingTest {
bobSession.spaceService().setSpaceParent(bobRoomId, spaceAInfo.spaceId, false, listOf(bobSession.sessionParams.homeServerHost ?: ""))
- it.countDown()
}
commonTestHelper.waitWithLatch { latch ->
@@ -569,8 +576,9 @@ class SpaceHierarchyTest : InstrumentedTest {
commonTestHelper.waitWithLatch {
val room = bobSession.getRoom(bobRoomId)!!
val currentPLContent = room
- .getStateEvent(EventType.STATE_ROOM_POWER_LEVELS)
- ?.let { it.content.toModel() }
+ .getStateEvent(EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.IsEmpty)
+ ?.content
+ .toModel()
val newPowerLevelsContent = currentPLContent
?.setUserPowerLevel(aliceSession.myUserId, Role.Admin.value)
@@ -583,7 +591,7 @@ class SpaceHierarchyTest : InstrumentedTest {
commonTestHelper.waitWithLatch { latch ->
commonTestHelper.retryPeriodicallyWithLatch(latch) {
val powerLevelsHelper = aliceSession.getRoom(bobRoomId)!!
- .getStateEvent(EventType.STATE_ROOM_POWER_LEVELS)
+ .getStateEvent(EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.IsEmpty)
?.content
?.toModel()
?.let { PowerLevelsHelper(it) }
@@ -602,4 +610,82 @@ class SpaceHierarchyTest : InstrumentedTest {
}
}
}
+
+ @Test
+ fun testDirectParentNames() = runSessionTest(context()) { commonTestHelper ->
+ val aliceSession = commonTestHelper.createAccount("Alice", SessionTestParams(true))
+
+ val spaceAInfo = createPublicSpace(
+ commonTestHelper,
+ aliceSession, "SpaceA",
+ listOf(
+ Triple("A1", true /*auto-join*/, true/*canonical*/),
+ Triple("A2", true, true)
+ )
+ )
+
+ val spaceBInfo = createPublicSpace(
+ commonTestHelper,
+ aliceSession, "SpaceB",
+ listOf(
+ Triple("B1", true /*auto-join*/, true/*canonical*/),
+ Triple("B2", true, true),
+ Triple("B3", true, true)
+ )
+ )
+
+ // also add B1 in space A
+
+ val B1roomId = spaceBInfo.roomIds.first()
+ val viaServers = listOf(aliceSession.sessionParams.homeServerHost ?: "")
+
+ val spaceA = aliceSession.spaceService().getSpace(spaceAInfo.spaceId)
+ val spaceB = aliceSession.spaceService().getSpace(spaceBInfo.spaceId)
+ commonTestHelper.runBlockingTest {
+ spaceA!!.addChildren(B1roomId, viaServers, null, true)
+ }
+
+ commonTestHelper.waitWithLatch { latch ->
+ commonTestHelper.retryPeriodicallyWithLatch(latch) {
+ val roomSummary = aliceSession.getRoomSummary(B1roomId)
+ roomSummary != null &&
+ roomSummary.directParentNames.size == 2 &&
+ roomSummary.directParentNames.contains(spaceA!!.spaceSummary()!!.name) &&
+ roomSummary.directParentNames.contains(spaceB!!.spaceSummary()!!.name)
+ }
+ }
+
+ commonTestHelper.waitWithLatch { latch ->
+ commonTestHelper.retryPeriodicallyWithLatch(latch) {
+ val roomSummary = aliceSession.getRoomSummary(spaceAInfo.roomIds.first())
+ roomSummary != null &&
+ roomSummary.directParentNames.size == 1 &&
+ roomSummary.directParentNames.contains(spaceA!!.spaceSummary()!!.name)
+ }
+ }
+
+ val newAName = "FooBar"
+ commonTestHelper.runBlockingTest {
+ spaceA!!.asRoom().stateService().updateName(newAName)
+ }
+
+ commonTestHelper.waitWithLatch { latch ->
+ commonTestHelper.retryPeriodicallyWithLatch(latch) {
+ val roomSummary = aliceSession.getRoomSummary(B1roomId)
+ roomSummary != null &&
+ roomSummary.directParentNames.size == 2 &&
+ roomSummary.directParentNames.contains(newAName) &&
+ roomSummary.directParentNames.contains(spaceB!!.spaceSummary()!!.name)
+ }
+ }
+
+ commonTestHelper.waitWithLatch { latch ->
+ commonTestHelper.retryPeriodicallyWithLatch(latch) {
+ val roomSummary = aliceSession.getRoomSummary(spaceAInfo.roomIds.first())
+ roomSummary != null &&
+ roomSummary.directParentNames.size == 1 &&
+ roomSummary.directParentNames.contains(newAName)
+ }
+ }
+ }
}
diff --git a/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/InlineMaths.kt b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/InlineMaths.kt
index 3fe8d15696..556579942b 100644
--- a/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/InlineMaths.kt
+++ b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/InlineMaths.kt
@@ -26,14 +26,14 @@ internal class InlineMaths(private val delimiter: InlineDelimiter) : CustomNode(
override fun getOpeningDelimiter(): String {
return when (delimiter) {
- InlineDelimiter.SINGLE_DOLLAR -> "$"
+ InlineDelimiter.SINGLE_DOLLAR -> "$"
InlineDelimiter.ROUND_BRACKET_ESCAPED -> "\\("
}
}
override fun getClosingDelimiter(): String {
return when (delimiter) {
- InlineDelimiter.SINGLE_DOLLAR -> "$"
+ InlineDelimiter.SINGLE_DOLLAR -> "$"
InlineDelimiter.ROUND_BRACKET_ESCAPED -> "\\)"
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/Matrix.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/Matrix.kt
index 979201706b..953ebddcbf 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
@@ -17,6 +17,8 @@
package org.matrix.android.sdk.api
import android.content.Context
+import android.os.Handler
+import android.os.Looper
import androidx.lifecycle.ProcessLifecycleOwner
import androidx.work.Configuration
import androidx.work.WorkManager
@@ -25,10 +27,12 @@ import com.zhuinden.monarchy.Monarchy
import org.matrix.android.sdk.BuildConfig
import org.matrix.android.sdk.api.auth.AuthenticationService
import org.matrix.android.sdk.api.auth.HomeServerHistoryService
+import org.matrix.android.sdk.api.debug.DebugService
import org.matrix.android.sdk.api.legacy.LegacySessionImporter
import org.matrix.android.sdk.api.network.ApiInterceptorListener
import org.matrix.android.sdk.api.network.ApiPath
import org.matrix.android.sdk.api.raw.RawService
+import org.matrix.android.sdk.api.securestorage.SecureStorageService
import org.matrix.android.sdk.api.settings.LightweightSettingsStorage
import org.matrix.android.sdk.internal.SessionManager
import org.matrix.android.sdk.internal.di.DaggerMatrixComponent
@@ -54,6 +58,7 @@ class Matrix(context: Context, matrixConfiguration: MatrixConfiguration) {
@Inject internal lateinit var legacySessionImporter: LegacySessionImporter
@Inject internal lateinit var authenticationService: AuthenticationService
@Inject internal lateinit var rawService: RawService
+ @Inject internal lateinit var debugService: DebugService
@Inject internal lateinit var userAgentHolder: UserAgentHolder
@Inject internal lateinit var backgroundDetectionObserver: BackgroundDetectionObserver
@Inject internal lateinit var olmManager: OlmManager
@@ -62,6 +67,9 @@ class Matrix(context: Context, matrixConfiguration: MatrixConfiguration) {
@Inject internal lateinit var apiInterceptor: ApiInterceptor
@Inject internal lateinit var matrixWorkerFactory: MatrixWorkerFactory
@Inject internal lateinit var lightweightSettingsStorage: LightweightSettingsStorage
+ @Inject internal lateinit var secureStorageService: SecureStorageService
+
+ private val uiHandler = Handler(Looper.getMainLooper())
init {
val appContext = context.applicationContext
@@ -74,7 +82,9 @@ class Matrix(context: Context, matrixConfiguration: MatrixConfiguration) {
.build()
WorkManager.initialize(appContext, configuration)
}
- ProcessLifecycleOwner.get().lifecycle.addObserver(backgroundDetectionObserver)
+ uiHandler.post {
+ ProcessLifecycleOwner.get().lifecycle.addObserver(backgroundDetectionObserver)
+ }
}
/**
@@ -93,6 +103,11 @@ class Matrix(context: Context, matrixConfiguration: MatrixConfiguration) {
*/
fun rawService() = rawService
+ /**
+ * Return the DebugService.
+ */
+ fun debugService() = debugService
+
/**
* Return the LightweightSettingsStorage.
*/
@@ -108,6 +123,11 @@ class Matrix(context: Context, matrixConfiguration: MatrixConfiguration) {
*/
fun legacySessionImporter() = legacySessionImporter
+ /**
+ * Returns the SecureStorageService used to encrypt and decrypt sensitive data.
+ */
+ fun secureStorageService(): SecureStorageService = secureStorageService
+
/**
* Get the worker factory. The returned value has to be provided to `WorkConfiguration.Builder()`.
*/
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixConfiguration.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixConfiguration.kt
index 21106fba6c..893e90fb3e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixConfiguration.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixConfiguration.kt
@@ -17,6 +17,7 @@
package org.matrix.android.sdk.api
import okhttp3.ConnectionSpec
+import okhttp3.Interceptor
import org.matrix.android.sdk.api.crypto.MXCryptoConfig
import java.net.Proxy
@@ -65,4 +66,8 @@ data class MatrixConfiguration(
* Thread messages default enable/disabled value.
*/
val threadMessagesEnabledDefault: Boolean = false,
+ /**
+ * List of network interceptors, they will be added when building an OkHttp client.
+ */
+ val networkInterceptors: List = emptyList(),
)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixPatterns.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixPatterns.kt
index 82f39806c0..bae4b06a05 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixPatterns.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixPatterns.kt
@@ -156,6 +156,20 @@ object MatrixPatterns {
return matrixId?.substringAfter(":", missingDelimiterValue = "")?.takeIf { it.isNotEmpty() }
}
+ /**
+ * Extract user name from a matrix id.
+ *
+ * @param matrixId
+ * @return null if the input is not a valid matrixId
+ */
+ fun extractUserNameFromId(matrixId: String): String? {
+ return if (isUserId(matrixId)) {
+ matrixId.removePrefix("@").substringBefore(":", missingDelimiterValue = "")
+ } else {
+ null
+ }
+ }
+
/**
* Orders which are not strings, or do not consist solely of ascii characters in the range \x20 (space) to \x7E (~),
* or consist of more than 50 characters, are forbidden and the field should be ignored if received.
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/LoginType.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/LoginType.kt
new file mode 100644
index 0000000000..627a825679
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/LoginType.kt
@@ -0,0 +1,38 @@
+/*
+ * 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.auth
+
+enum class LoginType {
+ PASSWORD,
+ SSO,
+ UNSUPPORTED,
+ CUSTOM,
+ DIRECT,
+ UNKNOWN;
+
+ companion object {
+
+ fun fromName(name: String) = when (name) {
+ PASSWORD.name -> PASSWORD
+ SSO.name -> SSO
+ UNSUPPORTED.name -> UNSUPPORTED
+ CUSTOM.name -> CUSTOM
+ DIRECT.name -> DIRECT
+ else -> UNKNOWN
+ }
+ }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/converter.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/converter.kt
index c840a7453d..e2f16ceee8 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/converter.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/converter.kt
@@ -69,8 +69,8 @@ fun TermPolicies.toLocalizedLoginTerms(
// Search for language
policy.keys.forEach { policyKey ->
when (policyKey) {
- "version" -> Unit // Ignore
- userLanguage -> {
+ "version" -> Unit // Ignore
+ userLanguage -> {
// We found the data for the user language
userLanguageUrlAndName = extractUrlAndName(policy[policyKey])
}
@@ -78,7 +78,7 @@ fun TermPolicies.toLocalizedLoginTerms(
// We found default language
defaultLanguageUrlAndName = extractUrlAndName(policy[policyKey])
}
- else -> {
+ else -> {
if (firstUrlAndName == null) {
// Get at least some data
firstUrlAndName = extractUrlAndName(policy[policyKey])
@@ -89,7 +89,7 @@ fun TermPolicies.toLocalizedLoginTerms(
// Copy found language data by priority
when {
- userLanguageUrlAndName != null -> {
+ userLanguageUrlAndName != null -> {
localizedFlowDataLoginTermsLocalizedUrl = userLanguageUrlAndName!!.url
localizedFlowDataLoginTermsLocalizedName = userLanguageUrlAndName!!.name
}
@@ -97,7 +97,7 @@ fun TermPolicies.toLocalizedLoginTerms(
localizedFlowDataLoginTermsLocalizedUrl = defaultLanguageUrlAndName!!.url
localizedFlowDataLoginTermsLocalizedName = defaultLanguageUrlAndName!!.name
}
- firstUrlAndName != null -> {
+ firstUrlAndName != null -> {
localizedFlowDataLoginTermsLocalizedUrl = firstUrlAndName!!.url
localizedFlowDataLoginTermsLocalizedName = firstUrlAndName!!.name
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/LoginFlowResult.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/LoginFlowResult.kt
index 7d1407c0d8..5b6c1897bf 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/LoginFlowResult.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/LoginFlowResult.kt
@@ -21,5 +21,6 @@ data class LoginFlowResult(
val ssoIdentityProviders: List?,
val isLoginAndRegistrationSupported: Boolean,
val homeServerUrl: String,
- val isOutdatedHomeserver: Boolean
+ val isOutdatedHomeserver: Boolean,
+ val isLogoutDevicesSupported: Boolean
)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/SessionParams.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/SessionParams.kt
index e3815231d9..de227631ed 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/SessionParams.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/SessionParams.kt
@@ -16,6 +16,8 @@
package org.matrix.android.sdk.api.auth.data
+import org.matrix.android.sdk.api.auth.LoginType
+
/**
* This data class holds necessary data to open a session.
* You don't have to manually instantiate it.
@@ -34,7 +36,12 @@ data class SessionParams(
/**
* Set to false if the current token is not valid anymore. Application should not have to use this info.
*/
- val isTokenValid: Boolean
+ val isTokenValid: Boolean,
+
+ /**
+ * The authentication method that was used to create the session.
+ */
+ val loginType: LoginType,
) {
/*
* Shortcuts. Usually the application should only need to use these shortcuts
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/SsoIdentityProvider.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/SsoIdentityProvider.kt
index a0733dda97..773f5a8cc4 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/SsoIdentityProvider.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/SsoIdentityProvider.kt
@@ -66,17 +66,17 @@ data class SsoIdentityProvider(
private fun toPriority(): Int {
return when (brand) {
// We are on Android, so user is more likely to have a Google account
- BRAND_GOOGLE -> 5
+ BRAND_GOOGLE -> 5
// Facebook is also an important SSO provider
BRAND_FACEBOOK -> 4
// Twitter is more for professionals
- BRAND_TWITTER -> 3
+ BRAND_TWITTER -> 3
// Here it's very for techie people
BRAND_GITHUB,
- BRAND_GITLAB -> 2
+ BRAND_GITLAB -> 2
// And finally, if the account has been created with an iPhone...
- BRAND_APPLE -> 1
- else -> 0
+ BRAND_APPLE -> 1
+ else -> 0
}
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/login/LoginWizard.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/login/LoginWizard.kt
index 5b8d2328c7..145cdbdc22 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/login/LoginWizard.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/login/LoginWizard.kt
@@ -72,7 +72,9 @@ interface LoginWizard {
* Confirm the new password, once the user has checked their email
* When this method succeed, tha account password will be effectively modified.
*
- * @param newPassword the desired new password
+ * @param newPassword the desired new password.
+ * @param logoutAllDevices defaults to true, all devices will be logged out. False values will only be taken into account
+ * if [org.matrix.android.sdk.api.auth.data.LoginFlowResult.isLogoutDevicesSupported] is true.
*/
- suspend fun resetPasswordMailConfirmed(newPassword: String)
+ suspend fun resetPasswordMailConfirmed(newPassword: String, logoutAllDevices: Boolean = true)
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/registration/RegistrationFlowResponse.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/registration/RegistrationFlowResponse.kt
index 1252e93b84..98542d2086 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/registration/RegistrationFlowResponse.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/registration/RegistrationFlowResponse.kt
@@ -88,15 +88,15 @@ fun RegistrationFlowResponse.toFlowResult(): FlowResult {
val isMandatory = flows?.all { type in it.stages.orEmpty() } == true
val stage = when (type) {
- LoginFlowTypes.RECAPTCHA -> Stage.ReCaptcha(
+ LoginFlowTypes.RECAPTCHA -> Stage.ReCaptcha(
isMandatory, ((params?.get(type) as? Map<*, *>)?.get("public_key") as? String)
?: ""
)
- LoginFlowTypes.DUMMY -> Stage.Dummy(isMandatory)
- LoginFlowTypes.TERMS -> Stage.Terms(isMandatory, params?.get(type) as? TermPolicies ?: emptyMap())
+ LoginFlowTypes.DUMMY -> Stage.Dummy(isMandatory)
+ LoginFlowTypes.TERMS -> Stage.Terms(isMandatory, params?.get(type) as? TermPolicies ?: emptyMap())
LoginFlowTypes.EMAIL_IDENTITY -> Stage.Email(isMandatory)
- LoginFlowTypes.MSISDN -> Stage.Msisdn(isMandatory)
- else -> Stage.Other(isMandatory, type, (params?.get(type) as? Map<*, *>))
+ LoginFlowTypes.MSISDN -> Stage.Msisdn(isMandatory)
+ else -> Stage.Other(isMandatory, type, (params?.get(type) as? Map<*, *>))
}
if (type in completedStages.orEmpty()) {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/crypto/MXCryptoConfig.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/crypto/MXCryptoConfig.kt
index 9507ddda65..015cb6a1a2 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/crypto/MXCryptoConfig.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/crypto/MXCryptoConfig.kt
@@ -38,4 +38,5 @@ data class MXCryptoConfig constructor(
* You can limit request only to your sessions by turning this setting to `true`
*/
val limitRoomKeyRequestsToMyDevices: Boolean = false,
-)
+
+ )
diff --git a/vector/src/main/java/im/vector/app/features/login2/created/AccountCreatedAction.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/debug/DebugService.kt
similarity index 55%
rename from vector/src/main/java/im/vector/app/features/login2/created/AccountCreatedAction.kt
rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/debug/DebugService.kt
index f108bfa886..d0cee08831 100644
--- a/vector/src/main/java/im/vector/app/features/login2/created/AccountCreatedAction.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/debug/DebugService.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 New Vector Ltd
+ * Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,12 +14,21 @@
* limitations under the License.
*/
-package im.vector.app.features.login2.created
+package org.matrix.android.sdk.api.debug
-import android.net.Uri
-import im.vector.app.core.platform.VectorViewModelAction
+import io.realm.RealmConfiguration
-sealed class AccountCreatedAction : VectorViewModelAction {
- data class SetDisplayName(val displayName: String) : AccountCreatedAction()
- data class SetAvatar(val avatarUri: Uri, val filename: String) : AccountCreatedAction()
+/**
+ * Useful methods to access to some private data managed by the SDK.
+ */
+interface DebugService {
+ /**
+ * Get all the available Realm Configuration.
+ */
+ fun getAllRealmConfigurations(): List
+
+ /**
+ * Prints out info on DB size to logcat.
+ */
+ fun logDbUsageInfo()
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/extensions/Strings.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/extensions/Strings.kt
index 2a8848e80a..9f979098f8 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/extensions/Strings.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/extensions/Strings.kt
@@ -19,7 +19,7 @@ package org.matrix.android.sdk.api.extensions
fun CharSequence.ensurePrefix(prefix: CharSequence): CharSequence {
return when {
startsWith(prefix) -> this
- else -> "$prefix$this"
+ else -> "$prefix$this"
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Extensions.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Extensions.kt
index d3cc8fc8e4..68b931b33c 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Extensions.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Extensions.kt
@@ -62,7 +62,10 @@ fun Throwable.isUsernameInUse() = this is Failure.ServerError &&
error.code == MatrixError.M_USER_IN_USE
fun Throwable.isInvalidUsername() = this is Failure.ServerError &&
- error.code == MatrixError.M_INVALID_USERNAME
+ (error.code == MatrixError.M_INVALID_USERNAME || usernameContainsNonAsciiCharacters())
+
+private fun Failure.ServerError.usernameContainsNonAsciiCharacters() = error.code == MatrixError.M_UNKNOWN &&
+ error.message == "Query parameter \'username\' must be ascii"
fun Throwable.isInvalidPassword() = this is Failure.ServerError &&
error.code == MatrixError.M_FORBIDDEN &&
@@ -86,6 +89,10 @@ fun Throwable.isInvalidUIAAuth() = this is Failure.ServerError &&
fun Throwable.isHomeserverUnavailable() = this is Failure.NetworkConnection &&
this.ioException is UnknownHostException
+fun Throwable.isMissingEmailVerification() = this is Failure.ServerError &&
+ error.code == MatrixError.M_UNAUTHORIZED &&
+ error.message == "Unable to get validated threepid"
+
/**
* Try to convert to a RegistrationFlowResponse. Return null in the cases it's not possible
*/
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/network/ApiPath.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/network/ApiPath.kt
index baf33a59c5..f5e5628566 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/network/ApiPath.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/network/ApiPath.kt
@@ -162,7 +162,7 @@ enum class ApiPath(val path: String, val method: String) {
KICK_USER(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/kick", "POST"),
REDACT_EVENT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/redact/{eventId}/{txnId}", "PUT"),
REPORT_CONTENT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/report/{eventId}", "POST"),
- GET_ALIASES(NetworkConstants.URI_API_PREFIX_PATH_UNSTABLE + "org.matrix.msc2432/rooms/{roomId}/aliases", "GET"),
+ GET_ALIASES(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/aliases", "GET"),
SEND_TYPING_STATE(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/typing/{userId}", "PUT"),
PUT_TAG(NetworkConstants.URI_API_PREFIX_PATH_R0 + "user/{userId}/rooms/{roomId}/tags/{tag}", "PUT"),
DELETE_TAG(NetworkConstants.URI_API_PREFIX_PATH_R0 + "user/{userId}/rooms/{roomId}/tags/{tag}", "DELETE"),
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/network/ssl/Fingerprint.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/network/ssl/Fingerprint.kt
index 93e93fd292..2fc04013f9 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/network/ssl/Fingerprint.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/network/ssl/Fingerprint.kt
@@ -36,7 +36,7 @@ data class Fingerprint(
internal fun matchesCert(cert: X509Certificate): Boolean {
val o: Fingerprint? = when (hashType) {
HashType.SHA256 -> newSha256Fingerprint(cert)
- HashType.SHA1 -> newSha1Fingerprint(cert)
+ HashType.SHA1 -> newSha1Fingerprint(cert)
}
return equals(o)
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/query/QueryStringValue.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/query/QueryStringValue.kt
index f08c86885d..d3f6ec2287 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/query/QueryStringValue.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/query/QueryStringValue.kt
@@ -16,6 +16,11 @@
package org.matrix.android.sdk.api.query
+/**
+ * Only a subset of [QueryStringValue] are applicable to query the `stateKey` of a state event.
+ */
+sealed interface QueryStateEventValue
+
/**
* Basic query language. All these cases are mutually exclusive.
*/
@@ -33,22 +38,22 @@ sealed interface QueryStringValue {
/**
* The tested field has to be not null.
*/
- object IsNotNull : QueryStringValue
+ object IsNotNull : QueryStringValue, QueryStateEventValue
/**
* The tested field has to be empty.
*/
- object IsEmpty : QueryStringValue
+ object IsEmpty : QueryStringValue, QueryStateEventValue
/**
- * The tested field has to not empty.
+ * The tested field has to be not empty.
*/
- object IsNotEmpty : QueryStringValue
+ object IsNotEmpty : QueryStringValue, QueryStateEventValue
/**
* Interface to check String content.
*/
- sealed interface ContentQueryStringValue : QueryStringValue {
+ sealed interface ContentQueryStringValue : QueryStringValue, QueryStateEventValue {
val string: String
val case: Case
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/query/SpaceFilter.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/query/SpaceFilter.kt
index 6383412ffb..ccefd5855f 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/query/SpaceFilter.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/query/SpaceFilter.kt
@@ -35,9 +35,19 @@ sealed interface SpaceFilter {
* Used to get all the rooms that do not have the provided space in their parent hierarchy.
*/
data class ExcludeSpace(val spaceId: String) : SpaceFilter
+
+ /**
+ * Used to apply no filtering to the space.
+ */
+ object NoFilter : SpaceFilter
}
/**
* Return a [SpaceFilter.ActiveSpace] if the String is not null, or [SpaceFilter.OrphanRooms].
*/
fun String?.toActiveSpaceOrOrphanRooms(): SpaceFilter = this?.let { SpaceFilter.ActiveSpace(it) } ?: SpaceFilter.OrphanRooms
+
+/**
+ * Return a [SpaceFilter.ActiveSpace] if the String is not null, or [SpaceFilter.NoFilter].
+ */
+fun String?.toActiveSpaceOrNoFilter(): SpaceFilter = this?.let { SpaceFilter.ActiveSpace(it) } ?: SpaceFilter.NoFilter
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/securestorage/SecretStoringUtils.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/securestorage/SecretStoringUtils.kt
similarity index 80%
rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/securestorage/SecretStoringUtils.kt
rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/securestorage/SecretStoringUtils.kt
index 07a5cbe5a0..e701e0f3ba 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/securestorage/SecretStoringUtils.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/securestorage/SecretStoringUtils.kt
@@ -16,7 +16,7 @@
@file:Suppress("DEPRECATION")
-package org.matrix.android.sdk.internal.session.securestorage
+package org.matrix.android.sdk.api.securestorage
import android.annotation.SuppressLint
import android.content.Context
@@ -25,7 +25,7 @@ import android.security.KeyPairGeneratorSpec
import android.security.keystore.KeyGenParameterSpec
import android.security.keystore.KeyProperties
import androidx.annotation.RequiresApi
-import org.matrix.android.sdk.internal.util.system.BuildVersionSdkIntProvider
+import org.matrix.android.sdk.api.util.BuildVersionSdkIntProvider
import timber.log.Timber
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
@@ -80,9 +80,11 @@ import javax.security.auth.x500.X500Principal
* Important: Keys stored in the keystore can be wiped out (depends of the OS version, like for example if you
* add a pin or change the schema); So you might and with a useless pile of bytes.
*/
-internal class SecretStoringUtils @Inject constructor(
+class SecretStoringUtils @Inject constructor(
private val context: Context,
- private val buildVersionSdkIntProvider: BuildVersionSdkIntProvider
+ private val keyStore: KeyStore,
+ private val buildVersionSdkIntProvider: BuildVersionSdkIntProvider,
+ private val keyNeedsUserAuthentication: Boolean = false,
) {
companion object {
@@ -94,14 +96,24 @@ internal class SecretStoringUtils @Inject constructor(
private const val FORMAT_1: Byte = 1
}
- private val keyStore: KeyStore by lazy {
- KeyStore.getInstance(ANDROID_KEY_STORE).apply {
- load(null)
- }
- }
-
private val secureRandom = SecureRandom()
+ /**
+ * Allows creation of the crypto keys associated witht he [alias] before encrypting some value with it.
+ * @return A [KeyStore.Entry] with the keys.
+ */
+ @SuppressLint("NewApi")
+ fun ensureKey(alias: String): KeyStore.Entry {
+ when {
+ buildVersionSdkIntProvider.get() >= Build.VERSION_CODES.M -> getOrGenerateSymmetricKeyForAliasM(alias)
+ else -> getOrGenerateKeyPairForAlias(alias).privateKey
+ }
+ return keyStore.getEntry(alias, null)
+ }
+
+ /**
+ * Deletes the key associated with the [keyAlias] and logs any [KeyStoreException] that could happen.
+ */
fun safeDeleteKey(keyAlias: String) {
try {
keyStore.deleteEntry(keyAlias)
@@ -121,25 +133,25 @@ internal class SecretStoringUtils @Inject constructor(
*/
@SuppressLint("NewApi")
@Throws(Exception::class)
- fun securelyStoreString(secret: String, keyAlias: String): ByteArray {
+ fun securelyStoreBytes(secret: ByteArray, keyAlias: String): ByteArray {
return when {
- buildVersionSdkIntProvider.get() >= Build.VERSION_CODES.M -> encryptStringM(secret, keyAlias)
- else -> encryptString(secret, keyAlias)
+ buildVersionSdkIntProvider.get() >= Build.VERSION_CODES.M -> encryptBytesM(secret, keyAlias)
+ else -> encryptBytes(secret, keyAlias)
}
}
/**
- * Decrypt a secret that was encrypted by #securelyStoreString().
+ * Decrypt a secret that was encrypted by [securelyStoreBytes].
*/
@SuppressLint("NewApi")
@Throws(Exception::class)
- fun loadSecureSecret(encrypted: ByteArray, keyAlias: String): String {
+ fun loadSecureSecretBytes(encrypted: ByteArray, keyAlias: String): ByteArray {
encrypted.inputStream().use { inputStream ->
// First get the format
return when (val format = inputStream.read().toByte()) {
- FORMAT_API_M -> decryptStringM(inputStream, keyAlias)
- FORMAT_1 -> decryptString(inputStream, keyAlias)
- else -> throw IllegalArgumentException("Unknown format $format")
+ FORMAT_API_M -> decryptBytesM(inputStream, keyAlias)
+ FORMAT_1 -> decryptBytes(inputStream, keyAlias)
+ else -> throw IllegalArgumentException("Unknown format $format")
}
}
}
@@ -148,7 +160,7 @@ internal class SecretStoringUtils @Inject constructor(
fun securelyStoreObject(any: Any, keyAlias: String, output: OutputStream) {
when {
buildVersionSdkIntProvider.get() >= Build.VERSION_CODES.M -> saveSecureObjectM(keyAlias, output, any)
- else -> saveSecureObject(keyAlias, output, any)
+ else -> saveSecureObject(keyAlias, output, any)
}
}
@@ -157,11 +169,27 @@ internal class SecretStoringUtils @Inject constructor(
// First get the format
return when (val format = inputStream.read().toByte()) {
FORMAT_API_M -> loadSecureObjectM(keyAlias, inputStream)
- FORMAT_1 -> loadSecureObject(keyAlias, inputStream)
- else -> throw IllegalArgumentException("Unknown format $format")
+ FORMAT_1 -> loadSecureObject(keyAlias, inputStream)
+ else -> throw IllegalArgumentException("Unknown format $format")
}
}
+ fun getEncryptCipher(alias: String): Cipher {
+ val key = when (val keyEntry = ensureKey(alias)) {
+ is KeyStore.SecretKeyEntry -> keyEntry.secretKey
+ is KeyStore.PrivateKeyEntry -> keyEntry.certificate.publicKey
+ else -> throw IllegalStateException("Unknown KeyEntry type.")
+ }
+ val cipherAlgorithm = when {
+ buildVersionSdkIntProvider.get() >= Build.VERSION_CODES.M -> AES_MODE
+ else -> RSA_MODE
+ }
+ val cipher = Cipher.getInstance(cipherAlgorithm)
+ cipher.init(Cipher.ENCRYPT_MODE, key)
+ return cipher
+ }
+
+ @SuppressLint("NewApi")
@RequiresApi(Build.VERSION_CODES.M)
private fun getOrGenerateSymmetricKeyForAliasM(alias: String): SecretKey {
val secretKeyEntry = (keyStore.getEntry(alias, null) as? KeyStore.SecretKeyEntry)
@@ -176,6 +204,17 @@ internal class SecretStoringUtils @Inject constructor(
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.setKeySize(128)
+ .setUserAuthenticationRequired(keyNeedsUserAuthentication)
+ .apply {
+ if (keyNeedsUserAuthentication) {
+ buildVersionSdkIntProvider.whenAtLeast(Build.VERSION_CODES.N) {
+ setInvalidatedByBiometricEnrollment(true)
+ }
+ buildVersionSdkIntProvider.whenAtLeast(Build.VERSION_CODES.P) {
+ setUnlockedDeviceRequired(true)
+ }
+ }
+ }
.build()
generator.init(keyGenSpec)
return generator.generateKey()
@@ -216,19 +255,16 @@ internal class SecretStoringUtils @Inject constructor(
}
@RequiresApi(Build.VERSION_CODES.M)
- private fun encryptStringM(text: String, keyAlias: String): ByteArray {
- val secretKey = getOrGenerateSymmetricKeyForAliasM(keyAlias)
-
- val cipher = Cipher.getInstance(AES_MODE)
- cipher.init(Cipher.ENCRYPT_MODE, secretKey)
+ private fun encryptBytesM(byteArray: ByteArray, keyAlias: String): ByteArray {
+ val cipher = getEncryptCipher(keyAlias)
val iv = cipher.iv
// we happen the iv to the final result
- val encryptedBytes: ByteArray = cipher.doFinal(text.toByteArray(Charsets.UTF_8))
+ val encryptedBytes: ByteArray = cipher.doFinal(byteArray)
return formatMMake(iv, encryptedBytes)
}
@RequiresApi(Build.VERSION_CODES.M)
- private fun decryptStringM(inputStream: InputStream, keyAlias: String): String {
+ private fun decryptBytesM(inputStream: InputStream, keyAlias: String): ByteArray {
val (iv, encryptedText) = formatMExtract(inputStream)
val secretKey = getOrGenerateSymmetricKeyForAliasM(keyAlias)
@@ -237,10 +273,10 @@ internal class SecretStoringUtils @Inject constructor(
val spec = GCMParameterSpec(128, iv)
cipher.init(Cipher.DECRYPT_MODE, secretKey, spec)
- return String(cipher.doFinal(encryptedText), Charsets.UTF_8)
+ return cipher.doFinal(encryptedText)
}
- private fun encryptString(text: String, keyAlias: String): ByteArray {
+ private fun encryptBytes(byteArray: ByteArray, keyAlias: String): ByteArray {
// we generate a random symmetric key
val key = ByteArray(16)
secureRandom.nextBytes(key)
@@ -252,12 +288,12 @@ internal class SecretStoringUtils @Inject constructor(
val cipher = Cipher.getInstance(AES_MODE)
cipher.init(Cipher.ENCRYPT_MODE, sKey)
val iv = cipher.iv
- val encryptedBytes: ByteArray = cipher.doFinal(text.toByteArray(Charsets.UTF_8))
+ val encryptedBytes: ByteArray = cipher.doFinal(byteArray)
return format1Make(encryptedKey, iv, encryptedBytes)
}
- private fun decryptString(inputStream: InputStream, keyAlias: String): String {
+ private fun decryptBytes(inputStream: InputStream, keyAlias: String): ByteArray {
val (encryptedKey, iv, encrypted) = format1Extract(inputStream)
// we need to decrypt the key
@@ -266,16 +302,13 @@ internal class SecretStoringUtils @Inject constructor(
val spec = GCMParameterSpec(128, iv)
cipher.init(Cipher.DECRYPT_MODE, SecretKeySpec(sKeyBytes, "AES"), spec)
- return String(cipher.doFinal(encrypted), Charsets.UTF_8)
+ return cipher.doFinal(encrypted)
}
@RequiresApi(Build.VERSION_CODES.M)
@Throws(IOException::class)
private fun saveSecureObjectM(keyAlias: String, output: OutputStream, writeObject: Any) {
- val secretKey = getOrGenerateSymmetricKeyForAliasM(keyAlias)
-
- val cipher = Cipher.getInstance(AES_MODE)
- cipher.init(Cipher.ENCRYPT_MODE, secretKey/*, spec*/)
+ val cipher = getEncryptCipher(keyAlias)
val iv = cipher.iv
val bos1 = ByteArrayOutputStream()
@@ -362,10 +395,8 @@ internal class SecretStoringUtils @Inject constructor(
@Throws(Exception::class)
private fun rsaEncrypt(alias: String, secret: ByteArray): ByteArray {
- val privateKeyEntry = getOrGenerateKeyPairForAlias(alias)
// Encrypt the text
- val inputCipher = Cipher.getInstance(RSA_MODE)
- inputCipher.init(Cipher.ENCRYPT_MODE, privateKeyEntry.certificate.publicKey)
+ val inputCipher = getEncryptCipher(alias)
val outputStream = ByteArrayOutputStream()
CipherOutputStream(outputStream, inputCipher).use {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/securestorage/SecureStorageModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/securestorage/SecureStorageModule.kt
new file mode 100644
index 0000000000..37a40fd677
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/securestorage/SecureStorageModule.kt
@@ -0,0 +1,45 @@
+/*
+ * 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.securestorage
+
+import android.content.Context
+import dagger.Binds
+import dagger.Module
+import dagger.Provides
+import org.matrix.android.sdk.api.util.BuildVersionSdkIntProvider
+import org.matrix.android.sdk.api.util.DefaultBuildVersionSdkIntProvider
+import java.security.KeyStore
+
+@Module
+internal abstract class SecureStorageModule {
+
+ @Module
+ companion object {
+ @Provides
+ fun provideKeyStore(): KeyStore = KeyStore.getInstance("AndroidKeyStore").also { it.load(null) }
+
+ @Provides
+ fun provideSecretStoringUtils(
+ context: Context,
+ keyStore: KeyStore,
+ buildVersionSdkIntProvider: BuildVersionSdkIntProvider,
+ ): SecretStoringUtils = SecretStoringUtils(context, keyStore, buildVersionSdkIntProvider)
+ }
+
+ @Binds
+ abstract fun bindBuildVersionSdkIntProvider(provider: DefaultBuildVersionSdkIntProvider): BuildVersionSdkIntProvider
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/securestorage/SecureStorageService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/securestorage/SecureStorageService.kt
similarity index 93%
rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/securestorage/SecureStorageService.kt
rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/securestorage/SecureStorageService.kt
index 6b75c94cb2..e217611d96 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/securestorage/SecureStorageService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/securestorage/SecureStorageService.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package org.matrix.android.sdk.api.session.securestorage
+package org.matrix.android.sdk.api.securestorage
import java.io.InputStream
import java.io.OutputStream
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 2f1ae8cd87..63c1c25130 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt
@@ -17,8 +17,7 @@
package org.matrix.android.sdk.api.session
import androidx.annotation.MainThread
-import androidx.lifecycle.LiveData
-import kotlinx.coroutines.flow.SharedFlow
+import io.realm.RealmConfiguration
import okhttp3.OkHttpClient
import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
import org.matrix.android.sdk.api.auth.data.SessionParams
@@ -34,10 +33,8 @@ import org.matrix.android.sdk.api.session.crypto.CryptoService
import org.matrix.android.sdk.api.session.events.EventService
import org.matrix.android.sdk.api.session.file.ContentDownloadStateTracker
import org.matrix.android.sdk.api.session.file.FileService
-import org.matrix.android.sdk.api.session.group.GroupService
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilitiesService
import org.matrix.android.sdk.api.session.identity.IdentityService
-import org.matrix.android.sdk.api.session.initsync.SyncStatusService
import org.matrix.android.sdk.api.session.integrationmanager.IntegrationManagerService
import org.matrix.android.sdk.api.session.media.MediaService
import org.matrix.android.sdk.api.session.openid.OpenIdService
@@ -49,14 +46,12 @@ 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
-import org.matrix.android.sdk.api.session.securestorage.SecureStorageService
import org.matrix.android.sdk.api.session.securestorage.SharedSecretStorageService
import org.matrix.android.sdk.api.session.signout.SignOutService
import org.matrix.android.sdk.api.session.space.SpaceService
import org.matrix.android.sdk.api.session.statistics.StatisticsListener
import org.matrix.android.sdk.api.session.sync.FilterService
-import org.matrix.android.sdk.api.session.sync.SyncState
-import org.matrix.android.sdk.api.session.sync.model.SyncResponse
+import org.matrix.android.sdk.api.session.sync.SyncService
import org.matrix.android.sdk.api.session.terms.TermsService
import org.matrix.android.sdk.api.session.thirdparty.ThirdPartyService
import org.matrix.android.sdk.api.session.typing.TypingUsersTracker
@@ -98,59 +93,11 @@ interface Session {
@MainThread
fun open()
- /**
- * Requires a one time background sync.
- */
- fun requireBackgroundSync()
-
- /**
- * Launches infinite self rescheduling background syncs via the WorkManager.
- *
- * While dozing, syncs will only occur during maintenance windows.
- * For reliability it's recommended to also start a long running foreground service
- * along with disabling battery optimizations.
- */
- fun startAutomaticBackgroundSync(timeOutInSeconds: Long, repeatDelayInSeconds: Long)
-
- fun stopAnyBackgroundSync()
-
- /**
- * This method start the sync thread.
- */
- fun startSync(fromForeground: Boolean)
-
- /**
- * This method stop the sync thread.
- */
- fun stopSync()
-
/**
* Clear cache of the session.
*/
suspend fun clearCache()
- /**
- * This method allows to listen the sync state.
- * @return a [LiveData] of [SyncState].
- */
- fun getSyncStateLive(): LiveData
-
- /**
- * This method returns the current sync state.
- * @return the current [SyncState].
- */
- fun getSyncState(): SyncState
-
- /**
- * This method returns a flow of SyncResponse. New value will be pushed through the sync thread.
- */
- fun syncFlow(): SharedFlow
-
- /**
- * This methods return true if an initial sync has been processed.
- */
- fun hasAlreadySynced(): Boolean
-
/**
* This method allow to close a session. It does stop some services.
*/
@@ -206,11 +153,6 @@ interface Session {
*/
fun roomDirectoryService(): RoomDirectoryService
- /**
- * Returns the GroupService associated with the session.
- */
- fun groupService(): GroupService
-
/**
* Returns the UserService associated with the session.
*/
@@ -247,14 +189,9 @@ interface Session {
fun termsService(): TermsService
/**
- * Returns the SyncStatusService associated with the session.
+ * Returns the SyncService associated with the session.
*/
- fun syncStatusService(): SyncStatusService
-
- /**
- * Returns the SecureStorageService associated with the session.
- */
- fun secureStorageService(): SecureStorageService
+ fun syncService(): SyncService
/**
* Returns the ProfileService associated with the session.
@@ -386,7 +323,12 @@ interface Session {
fun getUiaSsoFallbackUrl(authenticationSessionId: String): String
/**
- * Maintenance API, allows to print outs info on DB size to logcat.
+ * Debug API, will print out info on DB size to logcat.
*/
fun logDbUsageInfo()
+
+ /**
+ * Debug API, return the list of all RealmConfiguration used by this session.
+ */
+ fun getRealmConfigurations(): List
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/account/AccountService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/account/AccountService.kt
index e3d52adfc5..094c66f6f7 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/account/AccountService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/account/AccountService.kt
@@ -24,13 +24,13 @@ import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor
interface AccountService {
/**
* Ask the homeserver to change the password.
+ *
* @param password Current password.
* @param newPassword New password
+ * @param logoutAllDevices defaults to true, all devices will be logged out. False values will only be taken into account
+ * if [org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities.canControlLogoutDevices] is true.
*/
- suspend fun changePassword(
- password: String,
- newPassword: String
- )
+ suspend fun changePassword(password: String, newPassword: String, logoutAllDevices: Boolean = true)
/**
* Deactivate the account.
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt
index 9cc87b6f71..a5e05f69e0 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt
@@ -40,6 +40,7 @@ import org.matrix.android.sdk.api.session.crypto.verification.VerificationServic
import org.matrix.android.sdk.api.session.events.model.Content
import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.events.model.content.RoomKeyWithHeldContent
+import org.matrix.android.sdk.internal.crypto.model.SessionInfo
interface CryptoService {
@@ -84,6 +85,20 @@ interface CryptoService {
fun isKeyGossipingEnabled(): Boolean
+ /**
+ * As per MSC3061.
+ * If true will make it possible to share part of e2ee room history
+ * on invite depending on the room visibility setting.
+ */
+ fun enableShareKeyOnInvite(enable: Boolean)
+
+ /**
+ * As per MSC3061.
+ * If true will make it possible to share part of e2ee room history
+ * on invite depending on the room visibility setting.
+ */
+ fun isShareKeysOnInviteEnabled(): Boolean
+
fun setRoomUnBlacklistUnverifiedDevices(roomId: String)
fun getDeviceTrackingStatus(userId: String): Int
@@ -171,11 +186,14 @@ interface CryptoService {
fun getSharedWithInfo(roomId: String?, sessionId: String): MXUsersDevicesMap
fun getWithHeldMegolmSession(roomId: String, sessionId: String): RoomKeyWithHeldContent?
- fun logDbUsageInfo()
-
/**
* Perform any background tasks that can be done before a message is ready to
* send, in order to speed up sending of the message.
*/
fun prepareToEncrypt(roomId: String, callback: MatrixCallback)
+
+ /**
+ * Share all inbound sessions of the last chunk messages to the provided userId devices.
+ */
+ suspend fun sendSharedHistoryKeys(roomId: String, userId: String, sessionInfoSet: Set?)
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupLastVersionResult.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupLastVersionResult.kt
index a7e985cea9..92510bb52e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupLastVersionResult.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupLastVersionResult.kt
@@ -24,5 +24,5 @@ sealed interface KeysBackupLastVersionResult {
fun KeysBackupLastVersionResult.toKeysVersionResult(): KeysVersionResult? = when (this) {
is KeysBackupLastVersionResult.KeysBackup -> keysVersionResult
- KeysBackupLastVersionResult.NoKeysBackup -> null
+ KeysBackupLastVersionResult.NoKeysBackup -> null
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/ForwardedRoomKeyContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/ForwardedRoomKeyContent.kt
index 3df4ef7c9a..664cd00e94 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/ForwardedRoomKeyContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/ForwardedRoomKeyContent.kt
@@ -69,5 +69,11 @@ data class ForwardedRoomKeyContent(
* private part of this key unless they have done device verification.
*/
@Json(name = "sender_claimed_ed25519_key")
- val senderClaimedEd25519Key: String? = null
+ val senderClaimedEd25519Key: String? = null,
+
+ /**
+ * MSC3061 Identifies keys that were sent when the room's visibility setting was set to world_readable or shared.
+ */
+ @Json(name = "org.matrix.msc3061.shared_history")
+ val sharedHistory: Boolean? = false,
)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/Event.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/Event.kt
index 7124d8a1a3..59dc6c434d 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/Event.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/Event.kt
@@ -202,7 +202,7 @@ data class Event(
* It will return a decrypted text message or an empty string otherwise.
*/
fun getDecryptedTextSummary(): String? {
- if (isRedacted()) return "Message Deleted"
+ if (isRedacted()) return "Message removed"
val text = getDecryptedValue() ?: run {
if (isPoll()) {
return getPollQuestion() ?: "created a poll."
@@ -212,13 +212,13 @@ data class Event(
return when {
isReplyRenderedInThread() || isQuote() -> ContentUtils.extractUsefulTextFromReply(text)
- isFileMessage() -> "sent a file."
- isAudioMessage() -> "sent an audio file."
- isImageMessage() -> "sent an image."
- isVideoMessage() -> "sent a video."
- isSticker() -> "sent a sticker"
- isPoll() -> getPollQuestion() ?: "created a poll."
- else -> text
+ isFileMessage() -> "sent a file."
+ isAudioMessage() -> "sent an audio file."
+ isImageMessage() -> "sent an image."
+ isVideoMessage() -> "sent a video."
+ isSticker() -> "sent a sticker"
+ isPoll() -> getPollQuestion() ?: "created a poll."
+ else -> text
}
}
@@ -318,35 +318,35 @@ fun Event.isTextMessage(): Boolean {
MessageType.MSGTYPE_TEXT,
MessageType.MSGTYPE_EMOTE,
MessageType.MSGTYPE_NOTICE -> true
- else -> false
+ else -> false
}
}
fun Event.isImageMessage(): Boolean {
return when (getMsgType()) {
MessageType.MSGTYPE_IMAGE -> true
- else -> false
+ else -> false
}
}
fun Event.isVideoMessage(): Boolean {
return when (getMsgType()) {
MessageType.MSGTYPE_VIDEO -> true
- else -> false
+ else -> false
}
}
fun Event.isAudioMessage(): Boolean {
return when (getMsgType()) {
MessageType.MSGTYPE_AUDIO -> true
- else -> false
+ else -> false
}
}
fun Event.isFileMessage(): Boolean {
return when (getMsgType()) {
MessageType.MSGTYPE_FILE -> true
- else -> false
+ else -> false
}
}
@@ -356,14 +356,14 @@ fun Event.isAttachmentMessage(): Boolean {
MessageType.MSGTYPE_AUDIO,
MessageType.MSGTYPE_VIDEO,
MessageType.MSGTYPE_FILE -> true
- else -> false
+ else -> false
}
}
fun Event.isLocationMessage(): Boolean {
return when (getMsgType()) {
MessageType.MSGTYPE_LOCATION -> true
- else -> false
+ else -> false
}
}
@@ -371,6 +371,8 @@ fun Event.isPoll(): Boolean = getClearType() in EventType.POLL_START || getClear
fun Event.isSticker(): Boolean = getClearType() == EventType.STICKER
+fun Event.isLiveLocation(): Boolean = getClearType() in EventType.STATE_ROOM_BEACON_INFO
+
fun Event.getRelationContent(): RelationDefaultContent? {
return if (isEncrypted()) {
content.toModel()?.relatesTo
@@ -378,9 +380,9 @@ fun Event.getRelationContent(): RelationDefaultContent? {
content.toModel()?.relatesTo ?: run {
// Special cases when there is only a local msgtype for some event types
when (getClearType()) {
- EventType.STICKER -> getClearContent().toModel()?.relatesTo
+ EventType.STICKER -> getClearContent().toModel()?.relatesTo
in EventType.BEACON_LOCATION_DATA -> getClearContent().toModel()?.relatesTo
- else -> null
+ else -> null
}
}
}
@@ -427,3 +429,6 @@ fun Event.getPollContent(): MessagePollContent? {
fun Event.supportsNotification() =
this.getClearType() in EventType.MESSAGE + EventType.POLL_START + EventType.STATE_ROOM_BEACON_INFO
+
+fun Event.isContentReportable() =
+ this.getClearType() in EventType.MESSAGE + EventType.STATE_ROOM_BEACON_INFO
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/EventType.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/EventType.kt
index fa3a9f6acd..8fdbba21c5 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/EventType.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/EventType.kt
@@ -87,7 +87,10 @@ object EventType {
// Key share events
const val ROOM_KEY_REQUEST = "m.room_key_request"
const val FORWARDED_ROOM_KEY = "m.forwarded_room_key"
- const val ROOM_KEY_WITHHELD = "org.matrix.room_key.withheld"
+ val ROOM_KEY_WITHHELD = StableUnstableId(
+ stable = "m.room_key.withheld",
+ unstable = "org.matrix.room_key.withheld"
+ )
const val REQUEST_SECRET = "m.secret.request"
const val SEND_SECRET = "m.secret.send"
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/system/BuildVersionSdkIntProvider.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/StableUnstableId.kt
similarity index 69%
rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/system/BuildVersionSdkIntProvider.kt
rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/StableUnstableId.kt
index 515656049a..c68a9e47f9 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/system/BuildVersionSdkIntProvider.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/StableUnstableId.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 The Matrix.org Foundation C.I.C.
+ * Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,11 +14,11 @@
* limitations under the License.
*/
-package org.matrix.android.sdk.internal.util.system
+package org.matrix.android.sdk.api.session.events.model
-internal interface BuildVersionSdkIntProvider {
- /**
- * Return the current version of the Android SDK.
- */
- fun get(): Int
+data class StableUnstableId(
+ val stable: String,
+ val unstable: String,
+) {
+ val values = listOf(stable, unstable)
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/content/RoomKeyContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/content/RoomKeyContent.kt
index 0830a566ab..5b18d29ea0 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/content/RoomKeyContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/content/RoomKeyContent.kt
@@ -38,5 +38,12 @@ data class RoomKeyContent(
// should be a Long but it is sometimes a double
@Json(name = "chain_index")
- val chainIndex: Any? = null
+ val chainIndex: Any? = null,
+
+ /**
+ * MSC3061 Identifies keys that were sent when the room's visibility setting was set to world_readable or shared.
+ */
+ @Json(name = "org.matrix.msc3061.shared_history")
+ val sharedHistory: Boolean? = false
+
)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/content/RoomKeyWithHeldContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/content/RoomKeyWithHeldContent.kt
index d58c3614a7..fb8b65c4f2 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/content/RoomKeyWithHeldContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/content/RoomKeyWithHeldContent.kt
@@ -98,12 +98,12 @@ enum class WithHeldCode(val value: String) {
companion object {
fun fromCode(code: String?): WithHeldCode? {
return when (code) {
- BLACKLISTED.value -> BLACKLISTED
- UNVERIFIED.value -> UNVERIFIED
+ BLACKLISTED.value -> BLACKLISTED
+ UNVERIFIED.value -> UNVERIFIED
UNAUTHORISED.value -> UNAUTHORISED
- UNAVAILABLE.value -> UNAVAILABLE
- NO_OLM.value -> NO_OLM
- else -> null
+ UNAVAILABLE.value -> UNAVAILABLE
+ NO_OLM.value -> NO_OLM
+ else -> null
}
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/group/Group.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/group/Group.kt
deleted file mode 100644
index 25c69e5025..0000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/group/Group.kt
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.matrix.android.sdk.api.session.group
-
-/**
- * This interface defines methods to interact within a group.
- */
-interface Group {
- val groupId: String
-
- /**
- * This methods allows you to refresh data about this group. It will be reflected on the GroupSummary.
- * The SDK also takes care of refreshing group data every hour.
- * @return a Cancelable to be able to cancel requests.
- */
- suspend fun fetchGroupData()
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/group/GroupService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/group/GroupService.kt
deleted file mode 100644
index 1968af222a..0000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/group/GroupService.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.matrix.android.sdk.api.session.group
-
-import androidx.lifecycle.LiveData
-import org.matrix.android.sdk.api.session.group.model.GroupSummary
-
-/**
- * This interface defines methods to get groups. It's implemented at the session level.
- */
-interface GroupService {
- /**
- * Get a group from a groupId.
- * @param groupId the groupId to look for.
- * @return the group with groupId or null
- */
- fun getGroup(groupId: String): Group?
-
- /**
- * Get a groupSummary from a groupId.
- * @param groupId the groupId to look for.
- * @return the groupSummary with groupId or null
- */
- fun getGroupSummary(groupId: String): GroupSummary?
-
- /**
- * Get a list of group summaries. This list is a snapshot of the data.
- * @return the list of [GroupSummary]
- */
- fun getGroupSummaries(groupSummaryQueryParams: GroupSummaryQueryParams): List
-
- /**
- * Get a live list of group summaries. This list is refreshed as soon as the data changes.
- * @return the [LiveData] of [GroupSummary]
- */
- fun getGroupSummariesLive(groupSummaryQueryParams: GroupSummaryQueryParams): LiveData>
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/group/GroupSummaryQueryParams.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/group/GroupSummaryQueryParams.kt
deleted file mode 100644
index 5104b3ee53..0000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/group/GroupSummaryQueryParams.kt
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.matrix.android.sdk.api.session.group
-
-import org.matrix.android.sdk.api.query.QueryStringValue
-import org.matrix.android.sdk.api.session.room.model.Membership
-
-fun groupSummaryQueryParams(init: (GroupSummaryQueryParams.Builder.() -> Unit) = {}): GroupSummaryQueryParams {
- return GroupSummaryQueryParams.Builder().apply(init).build()
-}
-
-/**
- * This class can be used to filter group summaries.
- */
-data class GroupSummaryQueryParams(
- val displayName: QueryStringValue,
- val memberships: List
-) {
-
- class Builder {
-
- var displayName: QueryStringValue = QueryStringValue.IsNotEmpty
- var memberships: List = Membership.all()
-
- fun build() = GroupSummaryQueryParams(
- displayName = displayName,
- memberships = memberships
- )
- }
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/group/model/GroupSummary.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/group/model/GroupSummary.kt
deleted file mode 100644
index ef50fce82f..0000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/group/model/GroupSummary.kt
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.matrix.android.sdk.api.session.group.model
-
-import org.matrix.android.sdk.api.session.room.model.Membership
-
-/**
- * This class holds some data of a group.
- * It can be retrieved through [org.matrix.android.sdk.api.session.group.GroupService]
- */
-data class GroupSummary(
- val groupId: String,
- val membership: Membership,
- val displayName: String = "",
- val shortDescription: String = "",
- val avatarUrl: String = "",
- val roomIds: List = emptyList(),
- val userIds: List = emptyList()
-)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilities.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilities.kt
index 5b06fdacae..b5d6d891e4 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilities.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilities.kt
@@ -54,7 +54,12 @@ data class HomeServerCapabilities(
/**
* True if the home server support threading.
*/
- val canUseThreading: Boolean = false
+ val canUseThreading: Boolean = false,
+
+ /**
+ * True if the home server supports controlling the logout of all devices when changing password.
+ */
+ val canControlLogoutDevices: Boolean = false
) {
enum class RoomCapabilitySupport {
@@ -81,13 +86,13 @@ data class HomeServerCapabilities(
val versionCap = roomVersions.supportedVersion.firstOrNull { it.version == preferred }
return when {
- versionCap == null -> {
+ versionCap == null -> {
RoomCapabilitySupport.UNKNOWN
}
versionCap.status == RoomVersionStatus.STABLE -> {
RoomCapabilitySupport.SUPPORTED
}
- else -> {
+ else -> {
RoomCapabilitySupport.SUPPORTED_UNSTABLE
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/identity/ThreePid.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/identity/ThreePid.kt
index 42d777849b..6bcf576824 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/identity/ThreePid.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/identity/ThreePid.kt
@@ -27,7 +27,7 @@ sealed class ThreePid(open val value: String) {
internal fun ThreePid.toMedium(): String {
return when (this) {
- is ThreePid.Email -> ThirdPartyIdentifier.MEDIUM_EMAIL
+ is ThreePid.Email -> ThirdPartyIdentifier.MEDIUM_EMAIL
is ThreePid.Msisdn -> ThirdPartyIdentifier.MEDIUM_MSISDN
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/initsync/SyncStatusService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/initsync/SyncStatusService.kt
deleted file mode 100644
index 7006e11751..0000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/initsync/SyncStatusService.kt
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.matrix.android.sdk.api.session.initsync
-
-import androidx.lifecycle.LiveData
-
-interface SyncStatusService {
-
- fun getSyncStatusLive(): LiveData
-
- sealed class Status {
- /**
- * For initial sync.
- */
- abstract class InitialSyncStatus : Status()
-
- object Idle : InitialSyncStatus()
- data class InitialSyncProgressing(
- val initSyncStep: InitSyncStep,
- val percentProgress: Int = 0
- ) : InitialSyncStatus()
-
- /**
- * For incremental sync.
- */
- abstract class IncrementalSyncStatus : Status()
-
- object IncrementalSyncIdle : IncrementalSyncStatus()
- data class IncrementalSyncParsing(
- val rooms: Int,
- val toDevice: Int
- ) : IncrementalSyncStatus()
-
- object IncrementalSyncError : IncrementalSyncStatus()
- object IncrementalSyncDone : IncrementalSyncStatus()
- }
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/MatrixToConverter.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/MatrixToConverter.kt
index a904e89681..c418b59df4 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/MatrixToConverter.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/MatrixToConverter.kt
@@ -38,12 +38,12 @@ object MatrixToConverter {
// URL is already a matrix.to
uriString.startsWith(PermalinkService.MATRIX_TO_URL_BASE) -> uri
// Web or client url
- SUPPORTED_PATHS.any { it in uriString } -> {
+ SUPPORTED_PATHS.any { it in uriString } -> {
val path = SUPPORTED_PATHS.first { it in uriString }
Uri.parse(PermalinkService.MATRIX_TO_URL_BASE + uriString.substringAfter(path))
}
// URL is not supported
- else -> null
+ else -> null
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkData.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkData.kt
index e8d9c89b54..fc46c92117 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkData.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkData.kt
@@ -54,7 +54,5 @@ sealed class PermalinkData {
data class UserLink(val userId: String) : PermalinkData()
- data class GroupLink(val groupId: String) : PermalinkData()
-
- data class FallbackLink(val uri: Uri) : PermalinkData()
+ data class FallbackLink(val uri: Uri, val isLegacyGroupLink: Boolean = false) : PermalinkData()
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkParser.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkParser.kt
index 9d078dc4b2..3dccc3fbf2 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkParser.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkParser.kt
@@ -61,27 +61,29 @@ object PermalinkParser {
val params = safeFragment
.split(MatrixPatterns.SEP_REGEX)
.filter { it.isNotEmpty() }
- .map { URLDecoder.decode(it, "UTF-8") }
.take(2)
+ val decodedParams = params
+ .map { URLDecoder.decode(it, "UTF-8") }
+
val identifier = params.getOrNull(0)
- val extraParameter = params.getOrNull(1)
+ val decodedIdentifier = decodedParams.getOrNull(0)
+ val extraParameter = decodedParams.getOrNull(1)
return when {
- identifier.isNullOrEmpty() -> PermalinkData.FallbackLink(uri)
- MatrixPatterns.isUserId(identifier) -> PermalinkData.UserLink(userId = identifier)
- MatrixPatterns.isGroupId(identifier) -> PermalinkData.GroupLink(groupId = identifier)
- MatrixPatterns.isRoomId(identifier) -> {
- handleRoomIdCase(fragment, identifier, matrixToUri, extraParameter, viaQueryParameters)
+ identifier.isNullOrEmpty() || decodedIdentifier.isNullOrEmpty() -> PermalinkData.FallbackLink(uri)
+ MatrixPatterns.isUserId(decodedIdentifier) -> PermalinkData.UserLink(userId = decodedIdentifier)
+ MatrixPatterns.isRoomId(decodedIdentifier) -> {
+ handleRoomIdCase(fragment, decodedIdentifier, matrixToUri, extraParameter, viaQueryParameters)
}
- MatrixPatterns.isRoomAlias(identifier) -> {
+ MatrixPatterns.isRoomAlias(decodedIdentifier) -> {
PermalinkData.RoomLink(
- roomIdOrAlias = identifier,
+ roomIdOrAlias = decodedIdentifier,
isRoomAlias = true,
eventId = extraParameter.takeIf { !it.isNullOrEmpty() && MatrixPatterns.isEventId(it) },
viaParameters = viaQueryParameters
)
}
- else -> PermalinkData.FallbackLink(uri)
+ else -> PermalinkData.FallbackLink(uri, MatrixPatterns.isGroupId(identifier))
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/Action.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/Action.kt
index 2b2930c1ba..6122aae972 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/Action.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/Action.kt
@@ -71,15 +71,15 @@ sealed class Action {
fun List.toJson(): List {
return map { action ->
when (action) {
- is Action.Notify -> Action.ACTION_NOTIFY
+ is Action.Notify -> Action.ACTION_NOTIFY
is Action.DoNotNotify -> Action.ACTION_DONT_NOTIFY
- is Action.Sound -> {
+ is Action.Sound -> {
mapOf(
Action.ACTION_OBJECT_SET_TWEAK_KEY to Action.ACTION_OBJECT_SET_TWEAK_VALUE_SOUND,
Action.ACTION_OBJECT_VALUE_KEY to action.sound
)
}
- is Action.Highlight -> {
+ is Action.Highlight -> {
mapOf(
Action.ACTION_OBJECT_SET_TWEAK_KEY to Action.ACTION_OBJECT_SET_TWEAK_VALUE_HIGHLIGHT,
Action.ACTION_OBJECT_VALUE_KEY to action.highlight
@@ -94,11 +94,11 @@ fun PushRule.getActions(): List {
actions.forEach { actionStrOrObj ->
when (actionStrOrObj) {
- Action.ACTION_NOTIFY -> Action.Notify
+ Action.ACTION_NOTIFY -> Action.Notify
Action.ACTION_DONT_NOTIFY -> Action.DoNotNotify
- is Map<*, *> -> {
+ is Map<*, *> -> {
when (actionStrOrObj[Action.ACTION_OBJECT_SET_TWEAK_KEY]) {
- Action.ACTION_OBJECT_SET_TWEAK_VALUE_SOUND -> {
+ Action.ACTION_OBJECT_SET_TWEAK_VALUE_SOUND -> {
(actionStrOrObj[Action.ACTION_OBJECT_VALUE_KEY] as? String)?.let { stringValue ->
Action.Sound(stringValue)
}
@@ -112,13 +112,13 @@ fun PushRule.getActions(): List {
// When the value is not there, default is true, says the spec
?: Action.Highlight(true)
}
- else -> {
+ else -> {
Timber.w("Unsupported set_tweak value ${actionStrOrObj[Action.ACTION_OBJECT_SET_TWEAK_KEY]}")
null
}
}
}
- else -> {
+ else -> {
Timber.w("Unsupported action type $actionStrOrObj")
null
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/ContainsDisplayNameCondition.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/ContainsDisplayNameCondition.kt
index 69dd14ddc2..0bf14345b9 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/ContainsDisplayNameCondition.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/ContainsDisplayNameCondition.kt
@@ -39,7 +39,7 @@ class ContainsDisplayNameCondition : Condition {
// EventType.ENCRYPTED -> {
// event.root.getClearContent()?.toModel()
// }
- else -> null
+ else -> null
} ?: return false
return message.body.caseInsensitiveFind(displayName)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/Kind.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/Kind.kt
index 463f3c2a73..bba6fe6026 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/Kind.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/Kind.kt
@@ -27,11 +27,11 @@ enum class Kind(val value: String) {
fun fromString(value: String): Kind {
return when (value) {
- "event_match" -> EventMatch
- "contains_display_name" -> ContainsDisplayName
- "room_member_count" -> RoomMemberCount
+ "event_match" -> EventMatch
+ "contains_display_name" -> ContainsDisplayName
+ "room_member_count" -> RoomMemberCount
"sender_notification_permission" -> SenderNotificationPermission
- else -> Unrecognised
+ else -> Unrecognised
}
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/RoomMemberCountCondition.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/RoomMemberCountCondition.kt
index 6973ff1372..db097fd92c 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/RoomMemberCountCondition.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/RoomMemberCountCondition.kt
@@ -47,8 +47,8 @@ class RoomMemberCountCondition(
val numMembers = room.membershipService().getNumberOfJoinedMembers()
return when (prefix) {
- "<" -> numMembers < count
- ">" -> numMembers > count
+ "<" -> numMembers < count
+ ">" -> numMembers > count
"<=" -> numMembers <= count
">=" -> numMembers >= count
else -> numMembers == count
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/rest/PushCondition.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/rest/PushCondition.kt
index 1fc8329535..ec0936e4c8 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/rest/PushCondition.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/rest/PushCondition.kt
@@ -61,7 +61,7 @@ data class PushCondition(
fun asExecutableCondition(rule: PushRule): Condition? {
return when (Kind.fromString(kind)) {
- Kind.EventMatch -> {
+ Kind.EventMatch -> {
if (key != null && pattern != null) {
EventMatchCondition(key, pattern, rule.ruleId == RuleIds.RULE_ID_CONTAIN_USER_NAME)
} else {
@@ -69,10 +69,10 @@ data class PushCondition(
null
}
}
- Kind.ContainsDisplayName -> {
+ Kind.ContainsDisplayName -> {
ContainsDisplayNameCondition()
}
- Kind.RoomMemberCount -> {
+ Kind.RoomMemberCount -> {
if (iz.isNullOrEmpty()) {
Timber.e("Malformed ROOM_MEMBER_COUNT condition")
null
@@ -88,7 +88,7 @@ data class PushCondition(
SenderNotificationPermissionCondition(key)
}
}
- Kind.Unrecognised -> {
+ Kind.Unrecognised -> {
Timber.e("Unknown kind $kind")
null
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomExtensions.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomExtensions.kt
index 0e631427bd..b30c60554f 100644
--- 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
@@ -16,18 +16,21 @@
package org.matrix.android.sdk.api.session.room
-import org.matrix.android.sdk.api.query.QueryStringValue
+import org.matrix.android.sdk.api.query.QueryStateEventValue
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.
+ * @param eventId The id of the event to retrieve
*/
fun Room.getTimelineEvent(eventId: String): TimelineEvent? =
timelineService().getTimelineEvent(eventId)
/**
* Get a StateEvent using the StateService of a Room.
+ * @param eventType The type of the event, see [org.matrix.android.sdk.api.session.events.model.EventType].
+ * @param stateKey the query which will be done on the stateKey.
*/
-fun Room.getStateEvent(eventType: String, stateKey: QueryStringValue = QueryStringValue.NoCondition): Event? =
+fun Room.getStateEvent(eventType: String, stateKey: QueryStateEventValue): Event? =
stateService().getStateEvent(eventType, stateKey)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomService.kt
index 5dfb8961e3..ad8106c9c1 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomService.kt
@@ -40,6 +40,18 @@ interface RoomService {
*/
suspend fun createRoom(createRoomParams: CreateRoomParams): String
+ /**
+ * Create a room locally.
+ * This room will not be synchronized with the server and will not come back from the sync, so all the events related to this room will be generated
+ * locally.
+ */
+ suspend fun createLocalRoom(createRoomParams: CreateRoomParams): String
+
+ /**
+ * Delete a local room with all its related events.
+ */
+ suspend fun deleteLocalRoom(roomId: String)
+
/**
* Create a direct room asynchronously. This is a facility method to create a direct room with the necessary parameters.
*/
@@ -231,14 +243,11 @@ interface RoomService {
* @param queryParams The filter to use
* @param pagedListConfig The paged list configuration (page size, initial load, prefetch distance...)
* @param sortOrder defines how to sort the results
- * @param getFlattenParents When true, the list of known parents and grand parents summaries will be resolved.
- * This can have significant impact on performance, better be used only on manageable list (filtered by displayName, ..).
*/
fun getFilteredPagedRoomSummariesLive(
queryParams: RoomSummaryQueryParams,
pagedListConfig: PagedList.Config = defaultPagedListConfig,
sortOrder: RoomSortOrder = RoomSortOrder.ACTIVITY,
- getFlattenParents: Boolean = false,
): UpdatableLivePageResult
/**
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomSummaryQueryParams.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomSummaryQueryParams.kt
index 3d943473e4..60963ef25a 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomSummaryQueryParams.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomSummaryQueryParams.kt
@@ -86,11 +86,7 @@ data class RoomSummaryQueryParams(
/**
* Used to filter room using the current space.
*/
- val spaceFilter: SpaceFilter?,
- /**
- * Used to filter room using the current group.
- */
- val activeGroupId: String? = null
+ val spaceFilter: SpaceFilter,
) {
/**
@@ -105,8 +101,7 @@ data class RoomSummaryQueryParams(
var roomTagQueryFilter: RoomTagQueryFilter? = null
var excludeType: List? = listOf(RoomType.SPACE)
var includeType: List? = null
- var spaceFilter: SpaceFilter? = null
- var activeGroupId: String? = null
+ var spaceFilter: SpaceFilter = SpaceFilter.NoFilter
fun build() = RoomSummaryQueryParams(
displayName = displayName,
@@ -117,7 +112,6 @@ data class RoomSummaryQueryParams(
excludeType = excludeType,
includeType = includeType,
spaceFilter = spaceFilter,
- activeGroupId = activeGroupId
)
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/location/LocationSharingService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/location/LocationSharingService.kt
index dd48d51f45..cd8acbcccc 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/location/LocationSharingService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/location/LocationSharingService.kt
@@ -18,10 +18,61 @@ package org.matrix.android.sdk.api.session.room.location
import androidx.lifecycle.LiveData
import org.matrix.android.sdk.api.session.room.model.livelocation.LiveLocationShareAggregatedSummary
+import org.matrix.android.sdk.api.util.Cancelable
+import org.matrix.android.sdk.api.util.Optional
/**
* Manage all location sharing related features.
*/
interface LocationSharingService {
+ /**
+ * Send a static location event to the room.
+ * @param latitude required latitude of the location
+ * @param longitude required longitude of the location
+ * @param uncertainty Accuracy of the location in meters
+ * @param isUserLocation indicates whether the location data corresponds to the user location or not (pinned location)
+ */
+ suspend fun sendStaticLocation(latitude: Double, longitude: Double, uncertainty: Double?, isUserLocation: Boolean): Cancelable
+
+ /**
+ * Send a live location event to the room.
+ * To get the beacon info event id, [startLiveLocationShare] must be called before sending live location updates.
+ * @param beaconInfoEventId event id of the initial beacon info state event
+ * @param latitude required latitude of the location
+ * @param longitude required longitude of the location
+ * @param uncertainty Accuracy of the location in meters
+ */
+ suspend fun sendLiveLocation(beaconInfoEventId: String, latitude: Double, longitude: Double, uncertainty: Double?): Cancelable
+
+ /**
+ * Starts sharing live location in the room.
+ * @param timeoutMillis timeout of the live in milliseconds
+ * @param description description of the live for text fallback
+ * @return the result of the update of the live
+ */
+ suspend fun startLiveLocationShare(timeoutMillis: Long, description: String): UpdateLiveLocationShareResult
+
+ /**
+ * Stops sharing live location in the room.
+ * @return the result of the update of the live
+ */
+ suspend fun stopLiveLocationShare(): UpdateLiveLocationShareResult
+
+ /**
+ * Redact (delete) the live associated to the given beacon info event id.
+ * @param beaconInfoEventId event id of the initial beacon info state event
+ * @param reason Optional reason string
+ */
+ suspend fun redactLiveLocationShare(beaconInfoEventId: String, reason: String?)
+
+ /**
+ * Returns a LiveData on the list of current running live location shares.
+ */
fun getRunningLiveLocationShareSummaries(): LiveData>
+
+ /**
+ * Returns a LiveData on the live location share summary with the given eventId.
+ * @param beaconInfoEventId event id of the initial beacon info state event
+ */
+ fun getLiveLocationShareSummary(beaconInfoEventId: String): LiveData>
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/location/UpdateLiveLocationShareResult.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/location/UpdateLiveLocationShareResult.kt
new file mode 100644
index 0000000000..6f8c03be46
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/location/UpdateLiveLocationShareResult.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2022 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.api.session.room.location
+
+/**
+ * Represents the result of an update of live location share like a start or a stop.
+ */
+sealed interface UpdateLiveLocationShareResult {
+ data class Success(val beaconEventId: String) : UpdateLiveLocationShareResult
+ data class Failure(val error: Throwable) : UpdateLiveLocationShareResult
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/members/MembershipService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/members/MembershipService.kt
index e7ac69be74..144cfeb3b8 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/members/MembershipService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/members/MembershipService.kt
@@ -30,6 +30,20 @@ interface MembershipService {
*/
suspend fun loadRoomMembersIfNeeded()
+ /**
+ * All the room members can be not loaded, for instance after an initial sync.
+ * All the members will be loaded when calling [loadRoomMembersIfNeeded], or when sending an encrypted
+ * event to the room.
+ * The fun let the app know if all the members have been loaded for this room.
+ * @return true if all the members are loaded, or false elsewhere.
+ */
+ suspend fun areAllMembersLoaded(): Boolean
+
+ /**
+ * Live version for [areAllMembersLoaded].
+ */
+ fun areAllMembersLoadedLive(): LiveData
+
/**
* Return the roomMember with userId or null.
* @param userId the userId param to look for
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/PowerLevelsContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/PowerLevelsContent.kt
index 8ef94b2896..0329828130 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/PowerLevelsContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/PowerLevelsContent.kt
@@ -95,8 +95,8 @@ data class PowerLevelsContent(
// the first implementation was a string value
is String -> value.toInt()
is Double -> value.toInt()
- is Int -> value
- else -> Role.Moderator.value
+ is Int -> value
+ else -> Role.Moderator.value
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomGuestAccessContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomGuestAccessContent.kt
index ba274325bc..b229a35458 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomGuestAccessContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomGuestAccessContent.kt
@@ -29,14 +29,12 @@ data class RoomGuestAccessContent(
// Required. Whether guests can join the room. One of: ["can_join", "forbidden"]
@Json(name = "guest_access") val guestAccessStr: String? = null
) {
- val guestAccess: GuestAccess? = when (guestAccessStr) {
- "can_join" -> GuestAccess.CanJoin
- "forbidden" -> GuestAccess.Forbidden
- else -> {
- Timber.w("Invalid value for GuestAccess: `$guestAccessStr`")
- null
- }
- }
+ val guestAccess: GuestAccess? = GuestAccess.values()
+ .find { it.value == guestAccessStr }
+ ?: run {
+ Timber.w("Invalid value for GuestAccess: `$guestAccessStr`")
+ null
+ }
}
@JsonClass(generateAdapter = false)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomHistoryVisibility.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomHistoryVisibility.kt
index 06069f2646..eef986ef96 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomHistoryVisibility.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomHistoryVisibility.kt
@@ -23,28 +23,34 @@ import com.squareup.moshi.JsonClass
* Ref: https://matrix.org/docs/spec/client_server/latest#room-history-visibility
*/
@JsonClass(generateAdapter = false)
-enum class RoomHistoryVisibility {
+enum class RoomHistoryVisibility(val value: String) {
/**
* All events while this is the m.room.history_visibility value may be shared by any
* participating homeserver with anyone, regardless of whether they have ever joined the room.
*/
- @Json(name = "world_readable") WORLD_READABLE,
+ @Json(name = "world_readable") WORLD_READABLE("world_readable"),
/**
* Previous events are always accessible to newly joined members. All events in the
* room are accessible, even those sent when the member was not a part of the room.
*/
- @Json(name = "shared") SHARED,
+ @Json(name = "shared") SHARED("shared"),
/**
* Events are accessible to newly joined members from the point they were invited onwards.
* Events stop being accessible when the member's state changes to something other than invite or join.
*/
- @Json(name = "invited") INVITED,
+ @Json(name = "invited") INVITED("invited"),
/**
* Events are accessible to newly joined members from the point they joined the room onwards.
* Events stop being accessible when the member's state changes to something other than join.
*/
- @Json(name = "joined") JOINED
+ @Json(name = "joined") JOINED("joined")
}
+
+/**
+ * Room history should be shared only if room visibility is world_readable or shared.
+ */
+internal fun RoomHistoryVisibility.shouldShareHistory() =
+ this == RoomHistoryVisibility.WORLD_READABLE || this == RoomHistoryVisibility.SHARED
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomHistoryVisibilityContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomHistoryVisibilityContent.kt
index da5c90ff05..696cd8f613 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomHistoryVisibilityContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomHistoryVisibilityContent.kt
@@ -24,14 +24,10 @@ import timber.log.Timber
data class RoomHistoryVisibilityContent(
@Json(name = "history_visibility") val historyVisibilityStr: String? = null
) {
- val historyVisibility: RoomHistoryVisibility? = when (historyVisibilityStr) {
- "world_readable" -> RoomHistoryVisibility.WORLD_READABLE
- "shared" -> RoomHistoryVisibility.SHARED
- "invited" -> RoomHistoryVisibility.INVITED
- "joined" -> RoomHistoryVisibility.JOINED
- else -> {
- Timber.w("Invalid value for RoomHistoryVisibility: `$historyVisibilityStr`")
- null
- }
- }
+ val historyVisibility: RoomHistoryVisibility? = RoomHistoryVisibility.values()
+ .find { it.value == historyVisibilityStr }
+ ?: run {
+ Timber.w("Invalid value for RoomHistoryVisibility: `$historyVisibilityStr`")
+ null
+ }
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomJoinRulesContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomJoinRulesContent.kt
index 3b338a36cd..dbe21b1633 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomJoinRulesContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomJoinRulesContent.kt
@@ -36,12 +36,12 @@ data class RoomJoinRulesContent(
@Json(name = "allow") val allowList: List? = null
) {
val joinRules: RoomJoinRules? = when (joinRulesStr) {
- "public" -> RoomJoinRules.PUBLIC
- "invite" -> RoomJoinRules.INVITE
- "knock" -> RoomJoinRules.KNOCK
- "private" -> RoomJoinRules.PRIVATE
+ "public" -> RoomJoinRules.PUBLIC
+ "invite" -> RoomJoinRules.INVITE
+ "knock" -> RoomJoinRules.KNOCK
+ "private" -> RoomJoinRules.PRIVATE
"restricted" -> RoomJoinRules.RESTRICTED
- else -> {
+ else -> {
Timber.w("Invalid value for RoomJoinRules: `$joinRulesStr`")
null
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomSummary.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomSummary.kt
index 1ab23b7a11..ff4977491f 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomSummary.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomSummary.kt
@@ -164,9 +164,9 @@ data class RoomSummary(
*/
val spaceChildren: List? = null,
/**
- * List of all the space parents. Will be empty by default, you have to explicitly request it.
+ * The names of the room's direct space parents if any.
*/
- val flattenParents: List = emptyList(),
+ val directParentNames: List = emptyList(),
/**
* List of all the space parent Ids.
*/
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/VersioningState.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/VersioningState.kt
index 2e1668ebbb..8cfe3da031 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/VersioningState.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/VersioningState.kt
@@ -33,5 +33,7 @@ enum class VersioningState {
/**
* The room has been upgraded, and the new room has been joined.
*/
- UPGRADED_ROOM_JOINED,
+ UPGRADED_ROOM_JOINED;
+
+ fun isUpgraded() = this != NONE
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/RoomFeaturePreset.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/RoomFeaturePreset.kt
index 6487ad947f..3ed3e2d3a6 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/RoomFeaturePreset.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/RoomFeaturePreset.kt
@@ -16,7 +16,6 @@
package org.matrix.android.sdk.api.session.room.model.create
-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.homeserver.HomeServerCapabilities
@@ -30,7 +29,7 @@ interface RoomFeaturePreset {
fun updateRoomParams(params: CreateRoomParams)
- fun setupInitialStates(): List?
+ fun setupInitialStates(): List?
}
class RestrictedRoomPreset(val homeServerCapabilities: HomeServerCapabilities, val restrictedList: List) : RoomFeaturePreset {
@@ -41,9 +40,9 @@ class RestrictedRoomPreset(val homeServerCapabilities: HomeServerCapabilities, v
params.roomVersion = homeServerCapabilities.versionOverrideForFeature(HomeServerCapabilities.ROOM_CAP_RESTRICTED)
}
- override fun setupInitialStates(): List? {
+ override fun setupInitialStates(): List {
return listOf(
- Event(
+ CreateRoomStateEvent(
type = EventType.STATE_ROOM_JOIN_RULES,
stateKey = "",
content = RoomJoinRulesContent(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/group/model/GroupRooms.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/localecho/RoomLocalEcho.kt
similarity index 58%
rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/group/model/GroupRooms.kt
rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/localecho/RoomLocalEcho.kt
index 9e5d18225b..7ef0d63924 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/group/model/GroupRooms.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/localecho/RoomLocalEcho.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
+ * 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.
@@ -14,15 +14,18 @@
* limitations under the License.
*/
-package org.matrix.android.sdk.internal.session.group.model
+package org.matrix.android.sdk.api.session.room.model.localecho
-import com.squareup.moshi.Json
-import com.squareup.moshi.JsonClass
+import java.util.UUID
-@JsonClass(generateAdapter = true)
-internal data class GroupRooms(
+object RoomLocalEcho {
- @Json(name = "total_room_count_estimate") val totalRoomCountEstimate: Int? = null,
- @Json(name = "chunk") val rooms: List = emptyList()
+ private const val PREFIX = "!local."
-)
+ /**
+ * Tell whether the provider room id is a local id.
+ */
+ fun isLocalEchoId(roomId: String) = roomId.startsWith(PREFIX)
+
+ internal fun createLocalEchoId() = "${PREFIX}${UUID.randomUUID()}"
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/LocationInfo.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/LocationInfo.kt
index a1fd3bd2ec..e0a7846167 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/LocationInfo.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/LocationInfo.kt
@@ -22,7 +22,7 @@ import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
data class LocationInfo(
/**
- * Required. RFC5870 formatted geo uri 'geo:latitude,longitude;uncertainty' like 'geo:40.05,29.24;30' representing this location.
+ * Required. RFC5870 formatted geo uri 'geo:latitude,longitude;u=uncertainty' like 'geo:40.05,29.24;u=30' representing this location.
*/
@Json(name = "uri") val geoUri: String? = null,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageBeaconLocationDataContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageBeaconLocationDataContent.kt
index e261ab5206..aa2777d0a6 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageBeaconLocationDataContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageBeaconLocationDataContent.kt
@@ -22,7 +22,7 @@ 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
+ * Content of the 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.
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 0a66a6e400..30420fd3c7 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
@@ -35,7 +35,7 @@ data class MessageLocationContent(
@Json(name = "body") override val body: String,
/**
- * Required. RFC5870 formatted geo uri 'geo:latitude,longitude;uncertainty' like 'geo:40.05,29.24;30' representing this location.
+ * Required. RFC5870 formatted geo uri 'geo:latitude,longitude;u=uncertainty' like 'geo:40.05,29.24;u=30' representing this location.
*/
@Json(name = "geo_uri") val geoUri: String,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/PollCreationInfo.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/PollCreationInfo.kt
index 81b034a809..ee31d5959e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/PollCreationInfo.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/PollCreationInfo.kt
@@ -25,4 +25,7 @@ data class PollCreationInfo(
@Json(name = "kind") val kind: PollType? = PollType.DISCLOSED_UNSTABLE,
@Json(name = "max_selections") val maxSelections: Int = 1,
@Json(name = "answers") val answers: List? = null
-)
+) {
+
+ fun isUndisclosed() = kind in listOf(PollType.UNDISCLOSED_UNSTABLE, PollType.UNDISCLOSED)
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/powerlevels/Role.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/powerlevels/Role.kt
index 5fe9bf6993..c5cc573458 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/powerlevels/Role.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/powerlevels/Role.kt
@@ -32,11 +32,11 @@ sealed class Role(open val value: Int) : Comparable {
// Order matters, default value should be checked after defined roles
fun fromValue(value: Int, default: Int): Role {
return when (value) {
- Admin.value -> Admin
+ Admin.value -> Admin
Moderator.value -> Moderator
Default.value,
- default -> Default
- else -> Custom(value)
+ default -> Default
+ else -> Custom(value)
}
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/SendService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/SendService.kt
index 661c3be5bd..9cf062356f 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/SendService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/SendService.kt
@@ -142,24 +142,6 @@ interface SendService {
*/
fun resendMediaMessage(localEcho: TimelineEvent): Cancelable
- /**
- * Send a location event to the room.
- * @param latitude required latitude of the location
- * @param longitude required longitude of the location
- * @param uncertainty Accuracy of the location in meters
- * @param isUserLocation indicates whether the location data corresponds to the user location or not
- */
- fun sendLocation(latitude: Double, longitude: Double, uncertainty: Double?, isUserLocation: Boolean): Cancelable
-
- /**
- * Send a live location event to the room. beacon_info state event has to be sent before sending live location updates.
- * @param beaconInfoEventId event id of the initial beacon info state event
- * @param latitude required latitude of the location
- * @param longitude required longitude of the location
- * @param uncertainty Accuracy of the location in meters
- */
- fun sendLiveLocation(beaconInfoEventId: String, latitude: Double, longitude: Double, uncertainty: Double?): Cancelable
-
/**
* Remove this failed message from the timeline.
* @param localEcho the unsent local echo
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/UserDraft.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/UserDraft.kt
index 4ede1a66fc..e16405b3c0 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/UserDraft.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/UserDraft.kt
@@ -33,7 +33,7 @@ sealed interface UserDraft {
fun isValid(): Boolean {
return when (this) {
is Regular -> content.isNotBlank()
- else -> true
+ else -> true
}
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/sender/SenderInfo.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/sender/SenderInfo.kt
index 4c308c355a..d629df8b16 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/sender/SenderInfo.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/sender/SenderInfo.kt
@@ -29,9 +29,9 @@ data class SenderInfo(
) {
val disambiguatedDisplayName: String
get() = when {
- displayName == null -> userId
+ displayName == null -> userId
displayName.replaceSpaceChars().isBlank() -> "$displayName ($userId)"
- isUniqueDisplayName -> displayName
- else -> "$displayName ($userId)"
+ isUniqueDisplayName -> displayName
+ else -> "$displayName ($userId)"
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/state/StateService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/state/StateService.kt
index c79171f156..6ca63c2c49 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
@@ -18,7 +18,7 @@ package org.matrix.android.sdk.api.session.room.state
import android.net.Uri
import androidx.lifecycle.LiveData
-import org.matrix.android.sdk.api.query.QueryStringValue
+import org.matrix.android.sdk.api.query.QueryStateEventValue
import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.room.model.GuestAccess
import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibility
@@ -66,19 +66,6 @@ interface StateService {
*/
suspend fun deleteAvatar()
- /**
- * Stops sharing live location in the room.
- * @param userId user id
- */
- suspend fun stopLiveLocation(userId: String)
-
- /**
- * Returns beacon info state event of a user.
- * @param userId user id who is sharing location
- * @param filterOnlyLive filters only ongoing live location sharing beacons if true else ended event is included
- */
- suspend fun getLiveLocationBeaconInfo(userId: String, filterOnlyLive: Boolean): Event?
-
/**
* Send a state event to the room.
* @param eventType The type of event to send.
@@ -93,28 +80,28 @@ interface StateService {
* @param eventType An eventType.
* @param stateKey the query which will be done on the stateKey
*/
- fun getStateEvent(eventType: String, stateKey: QueryStringValue = QueryStringValue.NoCondition): Event?
+ fun getStateEvent(eventType: String, stateKey: QueryStateEventValue): Event?
/**
* Get a live state event of the room.
* @param eventType An eventType.
* @param stateKey the query which will be done on the stateKey
*/
- fun getStateEventLive(eventType: String, stateKey: QueryStringValue = QueryStringValue.NoCondition): LiveData>
+ fun getStateEventLive(eventType: String, stateKey: QueryStateEventValue): LiveData>
/**
* Get state events of the room.
* @param eventTypes Set of eventType. If empty, all state events will be returned
* @param stateKey the query which will be done on the stateKey
*/
- fun getStateEvents(eventTypes: Set, stateKey: QueryStringValue = QueryStringValue.NoCondition): List
+ fun getStateEvents(eventTypes: Set, stateKey: QueryStateEventValue): List
/**
* Get live state events of the room.
* @param eventTypes Set of eventType to observe. If empty, all state events will be observed
* @param stateKey the query which will be done on the stateKey
*/
- fun getStateEventsLive(eventTypes: Set, stateKey: QueryStringValue = QueryStringValue.NoCondition): LiveData>
+ fun getStateEventsLive(eventTypes: Set, stateKey: QueryStateEventValue): LiveData>
suspend fun setJoinRulePublic()
suspend fun setJoinRuleInviteOnly()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/state/StateServiceExtension.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/state/StateServiceExtension.kt
index 9e45fc126d..6a9506fd9e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/state/StateServiceExtension.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/state/StateServiceExtension.kt
@@ -26,7 +26,7 @@ import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesContent
* Return true if a room can be joined by anyone (RoomJoinRules.PUBLIC).
*/
fun StateService.isPublic(): Boolean {
- return getStateEvent(EventType.STATE_ROOM_JOIN_RULES, QueryStringValue.NoCondition)
+ return getStateEvent(EventType.STATE_ROOM_JOIN_RULES, QueryStringValue.IsEmpty)
?.content
?.toModel()
?.joinRules == RoomJoinRules.PUBLIC
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 d4ade9b5b9..d391abf1e6 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
@@ -23,6 +23,7 @@ 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.getRelationContent
import org.matrix.android.sdk.api.session.events.model.isEdition
+import org.matrix.android.sdk.api.session.events.model.isLiveLocation
import org.matrix.android.sdk.api.session.events.model.isPoll
import org.matrix.android.sdk.api.session.events.model.isReply
import org.matrix.android.sdk.api.session.events.model.isSticker
@@ -139,11 +140,11 @@ fun TimelineEvent.getEditedEventId(): String? {
*/
fun TimelineEvent.getLastMessageContent(): MessageContent? {
return when (root.getClearType()) {
- EventType.STICKER -> root.getClearContent().toModel()
- in EventType.POLL_START -> (annotations?.editSummary?.latestContent ?: root.getClearContent()).toModel()
+ 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.BEACON_LOCATION_DATA -> (annotations?.editSummary?.latestContent ?: root.getClearContent()).toModel()
- else -> (annotations?.editSummary?.latestContent ?: root.getClearContent()).toModel()
+ in EventType.BEACON_LOCATION_DATA -> (annotations?.editSummary?.latestContent ?: root.getClearContent()).toModel()
+ else -> (annotations?.editSummary?.latestContent ?: root.getClearContent()).toModel()
}
}
@@ -165,6 +166,10 @@ fun TimelineEvent.isSticker(): Boolean {
return root.isSticker()
}
+fun TimelineEvent.isLiveLocation(): Boolean {
+ return root.isLiveLocation()
+}
+
/**
* Returns whether or not the event is a root thread event.
*/
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/initsync/InitSyncStep.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/InitialSyncStep.kt
similarity index 89%
rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/initsync/InitSyncStep.kt
rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/InitialSyncStep.kt
index 901c1b2ffb..c4a3638ac4 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/initsync/InitSyncStep.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/InitialSyncStep.kt
@@ -14,15 +14,14 @@
* limitations under the License.
*/
-package org.matrix.android.sdk.api.session.initsync
+package org.matrix.android.sdk.api.session.sync
-enum class InitSyncStep {
+enum class InitialSyncStep {
ServerComputing,
Downloading,
ImportingAccount,
ImportingAccountCrypto,
ImportingAccountRoom,
- ImportingAccountGroups,
ImportingAccountData,
ImportingAccountJoinedRooms,
ImportingAccountInvitedRooms,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/SyncRequestState.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/SyncRequestState.kt
new file mode 100644
index 0000000000..4e932d49de
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/SyncRequestState.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2022 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.api.session.sync
+
+sealed interface SyncRequestState {
+ /**
+ * For initial sync.
+ */
+ interface InitialSyncRequestState : SyncRequestState
+
+ object Idle : InitialSyncRequestState
+ data class InitialSyncProgressing(
+ val initialSyncStep: InitialSyncStep,
+ val percentProgress: Int = 0
+ ) : InitialSyncRequestState
+
+ /**
+ * For incremental sync.
+ */
+ interface IncrementalSyncRequestState : SyncRequestState
+
+ object IncrementalSyncIdle : IncrementalSyncRequestState
+ data class IncrementalSyncParsing(
+ val rooms: Int,
+ val toDevice: Int
+ ) : IncrementalSyncRequestState
+
+ object IncrementalSyncError : IncrementalSyncRequestState
+ object IncrementalSyncDone : IncrementalSyncRequestState
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/SyncService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/SyncService.kt
new file mode 100644
index 0000000000..71f7ab8494
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/SyncService.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2022 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.api.session.sync
+
+import androidx.lifecycle.LiveData
+import kotlinx.coroutines.flow.SharedFlow
+import org.matrix.android.sdk.api.session.sync.model.SyncResponse
+
+interface SyncService {
+ /**
+ * This method start the sync thread.
+ */
+ fun startSync(fromForeground: Boolean)
+
+ /**
+ * This method stop the sync thread.
+ */
+ fun stopSync()
+
+ /**
+ * Requires a one time background sync.
+ */
+ fun requireBackgroundSync()
+
+ /**
+ * Launches infinite self rescheduling background syncs via the WorkManager.
+ *
+ * While dozing, syncs will only occur during maintenance windows.
+ * For reliability it's recommended to also start a long running foreground service
+ * along with disabling battery optimizations.
+ */
+ fun startAutomaticBackgroundSync(timeOutInSeconds: Long, repeatDelayInSeconds: Long)
+
+ fun stopAnyBackgroundSync()
+
+ /**
+ * This method returns the current sync state.
+ * @return the current [SyncState].
+ */
+ fun getSyncState(): SyncState
+
+ /**
+ * This method allows to listen the sync state.
+ * @return a [LiveData] of [SyncState].
+ */
+ fun getSyncStateLive(): LiveData
+
+ /**
+ * Get the [SyncRequestState] as a SharedFlow.
+ */
+ fun getSyncRequestStateFlow(): SharedFlow
+
+ /**
+ * This method returns a flow of SyncResponse. New value will be pushed through the sync thread.
+ */
+ fun syncFlow(): SharedFlow
+
+ /**
+ * This methods return true if an initial sync has been processed.
+ */
+ fun hasAlreadySynced(): Boolean
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/job/SyncService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/job/SyncAndroidService.kt
similarity index 97%
rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/job/SyncService.kt
rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/job/SyncAndroidService.kt
index ac81be2174..8dee633b9c 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/job/SyncService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/job/SyncAndroidService.kt
@@ -46,7 +46,7 @@ import java.util.concurrent.atomic.AtomicBoolean
* in order to be able to perform a sync even if the app is not running.
* The and must be declared in the Manifest or the app using the SDK
*/
-abstract class SyncService : Service() {
+abstract class SyncAndroidService : Service() {
private var sessionId: String? = null
private var mIsSelfDestroyed: Boolean = false
@@ -84,7 +84,7 @@ abstract class SyncService : Service() {
stopMe()
}
}
- else -> {
+ else -> {
val isInit = initialize(intent)
onStart(isInitialSync)
if (isInit) {
@@ -158,9 +158,9 @@ abstract class SyncService : Service() {
// never do that in foreground, let the syncThread work
syncTask.execute(params)
// Start sync if we were doing an initial sync and the syncThread is not launched yet
- if (isInitialSync && session.getSyncState() == SyncState.Idle) {
+ if (isInitialSync && session.syncService().getSyncState() == SyncState.Idle) {
val isForeground = !backgroundDetectionObserver.isInBackground
- session.startSync(isForeground)
+ session.syncService().startSync(isForeground)
}
stopMe()
} catch (throwable: Throwable) {
@@ -210,7 +210,7 @@ abstract class SyncService : Service() {
session = sessionComponent.session()
sessionId = safeSessionId
syncTask = sessionComponent.syncTask()
- isInitialSync = !session.hasAlreadySynced()
+ isInitialSync = !session.syncService().hasAlreadySynced()
networkConnectivityChecker = sessionComponent.networkConnectivityChecker()
taskExecutor = sessionComponent.taskExecutor()
coroutineDispatchers = sessionComponent.coroutineDispatchers()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/model/GroupSyncProfile.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/model/GroupSyncProfile.kt
deleted file mode 100644
index 581e6824ee..0000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/model/GroupSyncProfile.kt
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.matrix.android.sdk.api.session.sync.model
-
-import com.squareup.moshi.Json
-import com.squareup.moshi.JsonClass
-
-@JsonClass(generateAdapter = true)
-data class GroupSyncProfile(
- /**
- * The name of the group, if any. May be nil.
- */
- @Json(name = "name") val name: String? = null,
-
- /**
- * The URL for the group's avatar. May be nil.
- */
- @Json(name = "avatar_url") val avatarUrl: String? = null
-)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/model/GroupsSyncResponse.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/model/GroupsSyncResponse.kt
deleted file mode 100644
index fd8710bbda..0000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/model/GroupsSyncResponse.kt
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.matrix.android.sdk.api.session.sync.model
-
-import com.squareup.moshi.Json
-import com.squareup.moshi.JsonClass
-
-@JsonClass(generateAdapter = true)
-data class GroupsSyncResponse(
- /**
- * Joined groups: An array of groups ids.
- */
- @Json(name = "join") val join: Map = emptyMap(),
-
- /**
- * Invitations. The groups that the user has been invited to: keys are groups ids.
- */
- @Json(name = "invite") val invite: Map = emptyMap(),
-
- /**
- * Left groups. An array of groups ids: the groups that the user has left or been banned from.
- */
- @Json(name = "leave") val leave: Map = emptyMap()
-)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/model/InvitedGroupSync.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/model/InvitedGroupSync.kt
deleted file mode 100644
index d41df9f0f6..0000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/model/InvitedGroupSync.kt
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.matrix.android.sdk.api.session.sync.model
-
-import com.squareup.moshi.Json
-import com.squareup.moshi.JsonClass
-
-@JsonClass(generateAdapter = true)
-data class InvitedGroupSync(
- /**
- * The identifier of the inviter.
- */
- @Json(name = "inviter") val inviter: String? = null,
-
- /**
- * The group profile.
- */
- @Json(name = "profile") val profile: GroupSyncProfile? = null
-)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/model/SyncResponse.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/model/SyncResponse.kt
index c70964a513..382d8a1740 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/model/SyncResponse.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/model/SyncResponse.kt
@@ -65,10 +65,4 @@ data class SyncResponse(
*/
@Json(name = "org.matrix.msc2732.device_unused_fallback_key_types")
val deviceUnusedFallbackKeyTypes: List? = null,
-
- /**
- * List of groups.
- */
- @Json(name = "groups") val groups: GroupsSyncResponse? = null
-
)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/widgets/WidgetService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/widgets/WidgetService.kt
index 8ad6500d25..c2094f46bd 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/widgets/WidgetService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/widgets/WidgetService.kt
@@ -17,7 +17,7 @@
package org.matrix.android.sdk.api.session.widgets
import androidx.lifecycle.LiveData
-import org.matrix.android.sdk.api.query.QueryStringValue
+import org.matrix.android.sdk.api.query.QueryStateEventValue
import org.matrix.android.sdk.api.session.events.model.Content
import org.matrix.android.sdk.api.session.widgets.model.Widget
@@ -49,7 +49,7 @@ interface WidgetService {
*/
fun getRoomWidgets(
roomId: String,
- widgetId: QueryStringValue = QueryStringValue.NoCondition,
+ widgetId: QueryStateEventValue,
widgetTypes: Set? = null,
excludedTypes: Set? = null
): List
@@ -70,7 +70,7 @@ interface WidgetService {
*/
fun getRoomWidgetsLive(
roomId: String,
- widgetId: QueryStringValue = QueryStringValue.NoCondition,
+ widgetId: QueryStateEventValue,
widgetTypes: Set? = null,
excludedTypes: Set? = null
): LiveData>
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/widgets/model/WidgetType.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/widgets/model/WidgetType.kt
index ee098f9bf2..f02fe4f9de 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/widgets/model/WidgetType.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/widgets/model/WidgetType.kt
@@ -28,7 +28,8 @@ private val DEFINED_TYPES by lazy {
WidgetType.StickerPicker,
WidgetType.Grafana,
WidgetType.Custom,
- WidgetType.IntegrationManager
+ WidgetType.IntegrationManager,
+ WidgetType.ElementCall,
)
}
@@ -47,6 +48,7 @@ sealed class WidgetType(open val preferred: String, open val legacy: String = pr
object Grafana : WidgetType("m.grafana")
object Custom : WidgetType("m.custom")
object IntegrationManager : WidgetType("m.integration_manager")
+ object ElementCall : WidgetType("io.element.call")
data class Fallback(override val preferred: String) : WidgetType(preferred)
fun matches(type: String): Boolean {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/BuildVersionSdkIntProvider.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/BuildVersionSdkIntProvider.kt
new file mode 100644
index 0000000000..900a2e237f
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/BuildVersionSdkIntProvider.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2021 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.api.util
+
+interface BuildVersionSdkIntProvider {
+ /**
+ * Return the current version of the Android SDK.
+ */
+ fun get(): Int
+
+ /**
+ * Checks the if the current OS version is equal or greater than [version].
+ * @return A `non-null` result if true, `null` otherwise.
+ */
+ fun whenAtLeast(version: Int, result: () -> T): T? {
+ return if (get() >= version) {
+ result()
+ } else null
+ }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/system/DefaultBuildVersionSdkIntProvider.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/DefaultBuildVersionSdkIntProvider.kt
similarity index 85%
rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/system/DefaultBuildVersionSdkIntProvider.kt
rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/DefaultBuildVersionSdkIntProvider.kt
index 806c6e9735..7f0024cafa 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/system/DefaultBuildVersionSdkIntProvider.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/DefaultBuildVersionSdkIntProvider.kt
@@ -14,12 +14,12 @@
* limitations under the License.
*/
-package org.matrix.android.sdk.internal.util.system
+package org.matrix.android.sdk.api.util
import android.os.Build
import javax.inject.Inject
-internal class DefaultBuildVersionSdkIntProvider @Inject constructor() :
+class DefaultBuildVersionSdkIntProvider @Inject constructor() :
BuildVersionSdkIntProvider {
override fun get() = Build.VERSION.SDK_INT
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/MatrixItem.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/MatrixItem.kt
index ec775d640e..974f1cfcbe 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/MatrixItem.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/MatrixItem.kt
@@ -18,7 +18,6 @@ package org.matrix.android.sdk.api.util
import org.matrix.android.sdk.BuildConfig
import org.matrix.android.sdk.api.extensions.tryOrNull
-import org.matrix.android.sdk.api.session.group.model.GroupSummary
import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary
import org.matrix.android.sdk.api.session.room.model.RoomSummary
import org.matrix.android.sdk.api.session.room.model.RoomType
@@ -113,19 +112,6 @@ sealed class MatrixItem(
override fun updateAvatar(newAvatar: String?) = copy(avatarUrl = newAvatar)
}
- data class GroupItem(
- override val id: String,
- override val displayName: String? = null,
- override val avatarUrl: String? = null
- ) :
- MatrixItem(id, displayName, avatarUrl) {
- init {
- if (BuildConfig.DEBUG) checkId()
- }
-
- override fun updateAvatar(newAvatar: String?) = copy(avatarUrl = newAvatar)
- }
-
protected fun checkId() {
if (!id.startsWith(getIdPrefix())) {
error("Wrong usage of MatrixItem: check the id $id should start with ${getIdPrefix()}")
@@ -138,20 +124,19 @@ sealed class MatrixItem(
* Return the prefix as defined in the matrix spec (and not extracted from the id).
*/
private fun getIdPrefix() = when (this) {
- is UserItem -> '@'
- is EventItem -> '$'
+ is UserItem -> '@'
+ is EventItem -> '$'
is SpaceItem,
is RoomItem,
is EveryoneInRoomItem -> '!'
- is RoomAliasItem -> '#'
- is GroupItem -> '+'
+ is RoomAliasItem -> '#'
}
fun firstLetterOfDisplayName(): String {
val displayName = when (this) {
// use the room display name for the notify everyone item
is EveryoneInRoomItem -> roomDisplayName
- else -> displayName
+ else -> displayName
}
return (displayName?.takeIf { it.isNotBlank() } ?: id)
.let { dn ->
@@ -196,8 +181,6 @@ sealed class MatrixItem(
fun User.toMatrixItem() = MatrixItem.UserItem(userId, displayName, avatarUrl)
-fun GroupSummary.toMatrixItem() = MatrixItem.GroupItem(groupId, displayName, avatarUrl)
-
fun RoomSummary.toMatrixItem() = if (roomType == RoomType.SPACE) {
MatrixItem.SpaceItem(roomId, displayName, avatarUrl)
} else {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/MimeTypes.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/MimeTypes.kt
index ef47775f1b..5ec0dedadf 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/MimeTypes.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/MimeTypes.kt
@@ -33,9 +33,15 @@ object MimeTypes {
const val Ogg = "audio/ogg"
+ const val PlainText = "text/plain"
+
fun String?.normalizeMimeType() = if (this == BadJpg) Jpeg else this
fun String?.isMimeTypeImage() = this?.startsWith("image/").orFalse()
fun String?.isMimeTypeVideo() = this?.startsWith("video/").orFalse()
fun String?.isMimeTypeAudio() = this?.startsWith("audio/").orFalse()
+ fun String?.isMimeTypeApplication() = this?.startsWith("application/").orFalse()
+ fun String?.isMimeTypeFile() = this?.startsWith("file/").orFalse()
+ fun String?.isMimeTypeText() = this?.startsWith("text/").orFalse()
+ fun String?.isMimeTypeAny() = this?.startsWith("*/").orFalse()
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/StringOrderUtils.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/StringOrderUtils.kt
index 83c8585941..1de0a36034 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/StringOrderUtils.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/StringOrderUtils.kt
@@ -76,7 +76,7 @@ object StringOrderUtils {
}
fun stringToBase(x: String, alphabet: CharArray): BigInteger {
- if (x.isEmpty()) throw IllegalArgumentException()
+ require(x.isNotEmpty())
val len = alphabet.size.toBigInteger()
var result = BigInteger("0")
x.reversed().forEachIndexed { index, c ->
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/SessionManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/SessionManager.kt
index 1950c62995..5f5bb1f951 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/SessionManager.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/SessionManager.kt
@@ -40,6 +40,13 @@ internal class SessionManager @Inject constructor(
return getOrCreateSessionComponent(sessionParams)
}
+ fun getLastSession(): Session? {
+ val sessionParams = sessionParamsStore.getLast()
+ return sessionParams?.let {
+ getOrCreateSession(it)
+ }
+ }
+
fun getOrCreateSession(sessionParams: SessionParams): Session {
return getOrCreateSessionComponent(sessionParams).session()
}
@@ -55,7 +62,7 @@ internal class SessionManager @Inject constructor(
fun stopSession(sessionId: String) {
val sessionComponent = sessionComponents[sessionId] ?: throw RuntimeException("You don't have a session for id $sessionId")
- sessionComponent.session().stopSync()
+ sessionComponent.session().syncService().stopSync()
}
fun getOrCreateSessionComponent(sessionParams: SessionParams): SessionComponent {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/AuthModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/AuthModule.kt
index ddb70be906..463692e574 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/AuthModule.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/AuthModule.kt
@@ -83,6 +83,9 @@ internal abstract class AuthModule {
@Binds
abstract fun bindSessionCreator(creator: DefaultSessionCreator): SessionCreator
+ @Binds
+ abstract fun bindSessionParamsCreator(creator: DefaultSessionParamsCreator): SessionParamsCreator
+
@Binds
abstract fun bindDirectLoginTask(task: DefaultDirectLoginTask): DirectLoginTask
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt
index c64f451a2c..446f931847 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt
@@ -22,6 +22,7 @@ import okhttp3.OkHttpClient
import org.matrix.android.sdk.api.MatrixPatterns
import org.matrix.android.sdk.api.MatrixPatterns.getServerName
import org.matrix.android.sdk.api.auth.AuthenticationService
+import org.matrix.android.sdk.api.auth.LoginType
import org.matrix.android.sdk.api.auth.data.Credentials
import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig
import org.matrix.android.sdk.api.auth.data.LoginFlowResult
@@ -40,6 +41,7 @@ import org.matrix.android.sdk.internal.auth.login.DefaultLoginWizard
import org.matrix.android.sdk.internal.auth.login.DirectLoginTask
import org.matrix.android.sdk.internal.auth.registration.DefaultRegistrationWizard
import org.matrix.android.sdk.internal.auth.version.Versions
+import org.matrix.android.sdk.internal.auth.version.doesServerSupportLogoutDevices
import org.matrix.android.sdk.internal.auth.version.isLoginAndRegistrationSupportedBySdk
import org.matrix.android.sdk.internal.auth.version.isSupportedBySdk
import org.matrix.android.sdk.internal.di.Unauthenticated
@@ -73,10 +75,7 @@ internal class DefaultAuthenticationService @Inject constructor(
}
override fun getLastAuthenticatedSession(): Session? {
- val sessionParams = sessionParamsStore.getLast()
- return sessionParams?.let {
- sessionManager.getOrCreateSession(it)
- }
+ return sessionManager.getLastSession()
}
override suspend fun getLoginFlowOfSession(sessionId: String): LoginFlowResult {
@@ -281,7 +280,7 @@ internal class DefaultAuthenticationService @Inject constructor(
getLoginFlowResult(newAuthAPI, versions, wellknownResult.homeServerUrl)
}
- else -> throw Failure.OtherServerError("", HttpsURLConnection.HTTP_NOT_FOUND /* 404 */)
+ else -> throw Failure.OtherServerError("", HttpsURLConnection.HTTP_NOT_FOUND /* 404 */)
}
}
@@ -295,7 +294,8 @@ internal class DefaultAuthenticationService @Inject constructor(
ssoIdentityProviders = loginFlowResponse.flows.orEmpty().firstOrNull { it.type == LoginFlowTypes.SSO }?.ssoIdentityProvider,
isLoginAndRegistrationSupported = versions.isLoginAndRegistrationSupportedBySdk(),
homeServerUrl = homeServerUrl,
- isOutdatedHomeserver = !versions.isSupportedBySdk()
+ isOutdatedHomeserver = !versions.isSupportedBySdk(),
+ isLogoutDevicesSupported = versions.doesServerSupportLogoutDevices()
)
}
@@ -362,7 +362,7 @@ internal class DefaultAuthenticationService @Inject constructor(
homeServerConnectionConfig: HomeServerConnectionConfig,
credentials: Credentials
): Session {
- return sessionCreator.createSession(credentials, homeServerConnectionConfig)
+ return sessionCreator.createSession(credentials, homeServerConnectionConfig, LoginType.SSO)
}
override suspend fun getWellKnownData(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/SessionCreator.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/SessionCreator.kt
index ba01146a4a..7dbb11c7fd 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/SessionCreator.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/SessionCreator.kt
@@ -16,69 +16,41 @@
package org.matrix.android.sdk.internal.auth
-import android.net.Uri
+import org.matrix.android.sdk.api.auth.LoginType
import org.matrix.android.sdk.api.auth.data.Credentials
import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig
-import org.matrix.android.sdk.api.auth.data.SessionParams
-import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.internal.SessionManager
-import timber.log.Timber
import javax.inject.Inject
internal interface SessionCreator {
- suspend fun createSession(credentials: Credentials, homeServerConnectionConfig: HomeServerConnectionConfig): Session
+
+ suspend fun createSession(
+ credentials: Credentials,
+ homeServerConnectionConfig: HomeServerConnectionConfig,
+ loginType: LoginType,
+ ): Session
}
internal class DefaultSessionCreator @Inject constructor(
private val sessionParamsStore: SessionParamsStore,
private val sessionManager: SessionManager,
private val pendingSessionStore: PendingSessionStore,
- private val isValidClientServerApiTask: IsValidClientServerApiTask
+ private val sessionParamsCreator: SessionParamsCreator,
) : SessionCreator {
/**
* Credentials can affect the homeServerConnectionConfig, override homeserver url and/or
* identity server url if provided in the credentials.
*/
- override suspend fun createSession(credentials: Credentials, homeServerConnectionConfig: HomeServerConnectionConfig): Session {
+ override suspend fun createSession(
+ credentials: Credentials,
+ homeServerConnectionConfig: HomeServerConnectionConfig,
+ loginType: LoginType,
+ ): Session {
// We can cleanup the pending session params
pendingSessionStore.delete()
-
- val overriddenUrl = credentials.discoveryInformation?.homeServer?.baseURL
- // remove trailing "/"
- ?.trim { it == '/' }
- ?.takeIf { it.isNotBlank() }
- // It can be the same value, so in this case, do not check again the validity
- ?.takeIf { it != homeServerConnectionConfig.homeServerUriBase.toString() }
- ?.also { Timber.d("Overriding homeserver url to $it (will check if valid)") }
- ?.let { Uri.parse(it) }
- ?.takeIf {
- // Validate the URL, if the configuration is wrong server side, do not override
- tryOrNull {
- isValidClientServerApiTask.execute(
- IsValidClientServerApiTask.Params(
- homeServerConnectionConfig.copy(homeServerUriBase = it)
- )
- )
- .also { Timber.d("Overriding homeserver url: $it") }
- } ?: true // In case of other error (no network, etc.), consider it is valid...
- }
-
- val sessionParams = SessionParams(
- credentials = credentials,
- homeServerConnectionConfig = homeServerConnectionConfig.copy(
- homeServerUriBase = overriddenUrl ?: homeServerConnectionConfig.homeServerUriBase,
- identityServerUri = credentials.discoveryInformation?.identityServer?.baseURL
- // remove trailing "/"
- ?.trim { it == '/' }
- ?.takeIf { it.isNotBlank() }
- ?.also { Timber.d("Overriding identity server url to $it") }
- ?.let { Uri.parse(it) }
- ?: homeServerConnectionConfig.identityServerUri
- ),
- isTokenValid = true)
-
+ val sessionParams = sessionParamsCreator.create(credentials, homeServerConnectionConfig, loginType)
sessionParamsStore.save(sessionParams)
return sessionManager.getOrCreateSession(sessionParams)
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/SessionParamsCreator.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/SessionParamsCreator.kt
new file mode 100644
index 0000000000..31ed9a1e85
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/SessionParamsCreator.kt
@@ -0,0 +1,83 @@
+/*
+ * 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.auth
+
+import android.net.Uri
+import org.matrix.android.sdk.api.auth.LoginType
+import org.matrix.android.sdk.api.auth.data.Credentials
+import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig
+import org.matrix.android.sdk.api.auth.data.SessionParams
+import org.matrix.android.sdk.api.extensions.tryOrNull
+import timber.log.Timber
+import javax.inject.Inject
+
+internal interface SessionParamsCreator {
+
+ suspend fun create(
+ credentials: Credentials,
+ homeServerConnectionConfig: HomeServerConnectionConfig,
+ loginType: LoginType,
+ ): SessionParams
+}
+
+internal class DefaultSessionParamsCreator @Inject constructor(
+ private val isValidClientServerApiTask: IsValidClientServerApiTask
+) : SessionParamsCreator {
+
+ override suspend fun create(
+ credentials: Credentials,
+ homeServerConnectionConfig: HomeServerConnectionConfig,
+ loginType: LoginType,
+ ) = SessionParams(
+ credentials = credentials,
+ homeServerConnectionConfig = homeServerConnectionConfig.overrideWithCredentials(credentials),
+ isTokenValid = true,
+ loginType = loginType,
+ )
+
+ private suspend fun HomeServerConnectionConfig.overrideWithCredentials(credentials: Credentials) = copy(
+ homeServerUriBase = credentials.getHomeServerUri(this) ?: homeServerUriBase,
+ identityServerUri = credentials.getIdentityServerUri() ?: identityServerUri
+ )
+
+ private suspend fun Credentials.getHomeServerUri(homeServerConnectionConfig: HomeServerConnectionConfig) =
+ discoveryInformation?.homeServer?.baseURL
+ ?.trim { it == '/' }
+ ?.takeIf { it.isNotBlank() }
+ // It can be the same value, so in this case, do not check again the validity
+ ?.takeIf { it != homeServerConnectionConfig.homeServerUriBase.toString() }
+ ?.also { Timber.d("Overriding homeserver url to $it (will check if valid)") }
+ ?.let { Uri.parse(it) }
+ ?.takeIf { validateUri(it, homeServerConnectionConfig) }
+
+ private suspend fun validateUri(uri: Uri, homeServerConnectionConfig: HomeServerConnectionConfig) =
+ // Validate the URL, if the configuration is wrong server side, do not override
+ tryOrNull {
+ performClientServerApiValidation(uri, homeServerConnectionConfig)
+ } ?: true // In case of other error (no network, etc.), consider it is valid...
+
+ private suspend fun performClientServerApiValidation(uri: Uri, homeServerConnectionConfig: HomeServerConnectionConfig) =
+ isValidClientServerApiTask.execute(
+ IsValidClientServerApiTask.Params(homeServerConnectionConfig.copy(homeServerUriBase = uri))
+ ).also { Timber.d("Overriding homeserver url: $it") }
+
+ private fun Credentials.getIdentityServerUri() = discoveryInformation?.identityServer?.baseURL
+ ?.trim { it == '/' }
+ ?.takeIf { it.isNotBlank() }
+ ?.also { Timber.d("Overriding identity server url to $it") }
+ ?.let { Uri.parse(it) }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/AuthRealmMigration.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/AuthRealmMigration.kt
index 88c6d04ee6..c5b8eae3ff 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/AuthRealmMigration.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/AuthRealmMigration.kt
@@ -17,15 +17,18 @@
package org.matrix.android.sdk.internal.auth.db
import io.realm.DynamicRealm
-import io.realm.RealmMigration
import org.matrix.android.sdk.internal.auth.db.migration.MigrateAuthTo001
import org.matrix.android.sdk.internal.auth.db.migration.MigrateAuthTo002
import org.matrix.android.sdk.internal.auth.db.migration.MigrateAuthTo003
import org.matrix.android.sdk.internal.auth.db.migration.MigrateAuthTo004
-import timber.log.Timber
+import org.matrix.android.sdk.internal.auth.db.migration.MigrateAuthTo005
+import org.matrix.android.sdk.internal.util.database.MatrixRealmMigration
import javax.inject.Inject
-internal class AuthRealmMigration @Inject constructor() : RealmMigration {
+internal class AuthRealmMigration @Inject constructor() : MatrixRealmMigration(
+ dbName = "Auth",
+ schemaVersion = 5L,
+) {
/**
* Forces all AuthRealmMigration instances to be equal.
* Avoids Realm throwing when multiple instances of the migration are set.
@@ -33,14 +36,11 @@ internal class AuthRealmMigration @Inject constructor() : RealmMigration {
override fun equals(other: Any?) = other is AuthRealmMigration
override fun hashCode() = 4000
- val schemaVersion = 4L
-
- override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) {
- Timber.d("Migrating Auth Realm from $oldVersion to $newVersion")
-
+ override fun doMigrate(realm: DynamicRealm, oldVersion: Long) {
if (oldVersion < 1) MigrateAuthTo001(realm).perform()
if (oldVersion < 2) MigrateAuthTo002(realm).perform()
if (oldVersion < 3) MigrateAuthTo003(realm).perform()
if (oldVersion < 4) MigrateAuthTo004(realm).perform()
+ if (oldVersion < 5) MigrateAuthTo005(realm).perform()
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/SessionParamsEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/SessionParamsEntity.kt
index ba1ab8147b..f6c883cac0 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/SessionParamsEntity.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/SessionParamsEntity.kt
@@ -26,5 +26,6 @@ internal open class SessionParamsEntity(
var homeServerConnectionConfigJson: String = "",
// Set to false when the token is invalid and the user has been soft logged out
// In case of hard logout, this object is deleted from DB
- var isTokenValid: Boolean = true
+ var isTokenValid: Boolean = true,
+ var loginType: String = "",
) : RealmObject()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/SessionParamsMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/SessionParamsMapper.kt
index 86929b1afe..23923bf267 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/SessionParamsMapper.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/SessionParamsMapper.kt
@@ -17,6 +17,7 @@
package org.matrix.android.sdk.internal.auth.db
import com.squareup.moshi.Moshi
+import org.matrix.android.sdk.api.auth.LoginType
import org.matrix.android.sdk.api.auth.data.Credentials
import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig
import org.matrix.android.sdk.api.auth.data.SessionParams
@@ -37,7 +38,7 @@ internal class SessionParamsMapper @Inject constructor(moshi: Moshi) {
if (credentials == null || homeServerConnectionConfig == null) {
return null
}
- return SessionParams(credentials, homeServerConnectionConfig, entity.isTokenValid)
+ return SessionParams(credentials, homeServerConnectionConfig, entity.isTokenValid, LoginType.fromName(entity.loginType))
}
fun map(sessionParams: SessionParams?): SessionParamsEntity? {
@@ -54,7 +55,8 @@ internal class SessionParamsMapper @Inject constructor(moshi: Moshi) {
sessionParams.userId,
credentialsJson,
homeServerConnectionConfigJson,
- sessionParams.isTokenValid
+ sessionParams.isTokenValid,
+ sessionParams.loginType.name,
)
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/migration/MigrateAuthTo005.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/migration/MigrateAuthTo005.kt
new file mode 100644
index 0000000000..2cf1b62a4c
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/migration/MigrateAuthTo005.kt
@@ -0,0 +1,35 @@
+/*
+ * 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.auth.db.migration
+
+import io.realm.DynamicRealm
+import org.matrix.android.sdk.api.auth.LoginType
+import org.matrix.android.sdk.internal.auth.db.SessionParamsEntityFields
+import org.matrix.android.sdk.internal.util.database.RealmMigrator
+import timber.log.Timber
+
+internal class MigrateAuthTo005(realm: DynamicRealm) : RealmMigrator(realm, 5) {
+
+ override fun doMigrate(realm: DynamicRealm) {
+ Timber.d("Update SessionParamsEntity to add LoginType")
+
+ realm.schema.get("SessionParamsEntity")
+ ?.addField(SessionParamsEntityFields.LOGIN_TYPE, String::class.java)
+ ?.setRequired(SessionParamsEntityFields.LOGIN_TYPE, true)
+ ?.transform { it.set(SessionParamsEntityFields.LOGIN_TYPE, LoginType.UNKNOWN.name) }
+ }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DefaultLoginWizard.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DefaultLoginWizard.kt
index 20b056f1c7..468e998407 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DefaultLoginWizard.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DefaultLoginWizard.kt
@@ -17,6 +17,7 @@
package org.matrix.android.sdk.internal.auth.login
import android.util.Patterns
+import org.matrix.android.sdk.api.auth.LoginType
import org.matrix.android.sdk.api.auth.login.LoginProfileInfo
import org.matrix.android.sdk.api.auth.login.LoginWizard
import org.matrix.android.sdk.api.auth.registration.RegisterThreePid
@@ -78,7 +79,7 @@ internal class DefaultLoginWizard(
authAPI.login(loginParams)
}
- return sessionCreator.createSession(credentials, pendingSessionData.homeServerConnectionConfig)
+ return sessionCreator.createSession(credentials, pendingSessionData.homeServerConnectionConfig, LoginType.PASSWORD)
}
/**
@@ -92,7 +93,7 @@ internal class DefaultLoginWizard(
authAPI.login(loginParams)
}
- return sessionCreator.createSession(credentials, pendingSessionData.homeServerConnectionConfig)
+ return sessionCreator.createSession(credentials, pendingSessionData.homeServerConnectionConfig, LoginType.SSO)
}
override suspend fun loginCustom(data: JsonDict): Session {
@@ -100,7 +101,7 @@ internal class DefaultLoginWizard(
authAPI.login(data)
}
- return sessionCreator.createSession(credentials, pendingSessionData.homeServerConnectionConfig)
+ return sessionCreator.createSession(credentials, pendingSessionData.homeServerConnectionConfig, LoginType.CUSTOM)
}
override suspend fun resetPassword(email: String) {
@@ -121,12 +122,13 @@ internal class DefaultLoginWizard(
.also { pendingSessionStore.savePendingSessionData(it) }
}
- override suspend fun resetPasswordMailConfirmed(newPassword: String) {
+ override suspend fun resetPasswordMailConfirmed(newPassword: String, logoutAllDevices: Boolean) {
val resetPasswordData = pendingSessionData.resetPasswordData ?: throw IllegalStateException("Developer error - Must call resetPassword first")
val param = ResetPasswordMailConfirmed.create(
pendingSessionData.clientSecret,
resetPasswordData.addThreePidRegistrationResponse.sid,
- newPassword
+ newPassword,
+ logoutAllDevices
)
executeRequest(null) {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DirectLoginTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DirectLoginTask.kt
index 28706c7e80..af42105756 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DirectLoginTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DirectLoginTask.kt
@@ -18,6 +18,7 @@ package org.matrix.android.sdk.internal.auth.login
import dagger.Lazy
import okhttp3.OkHttpClient
+import org.matrix.android.sdk.api.auth.LoginType
import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig
import org.matrix.android.sdk.api.failure.Failure
import org.matrix.android.sdk.api.session.Session
@@ -73,11 +74,11 @@ internal class DefaultDirectLoginTask @Inject constructor(
homeServerUrl,
throwable.fingerprint
)
- else -> throwable
+ else -> throwable
}
}
- return sessionCreator.createSession(credentials, params.homeServerConnectionConfig)
+ return sessionCreator.createSession(credentials, params.homeServerConnectionConfig, LoginType.DIRECT)
}
private fun buildClient(homeServerConnectionConfig: HomeServerConnectionConfig): OkHttpClient {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/ResetPasswordMailConfirmed.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/ResetPasswordMailConfirmed.kt
index 4e0c000f87..01481f70dc 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/ResetPasswordMailConfirmed.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/ResetPasswordMailConfirmed.kt
@@ -30,13 +30,17 @@ internal data class ResetPasswordMailConfirmed(
// the new password
@Json(name = "new_password")
- val newPassword: String? = null
+ val newPassword: String? = null,
+
+ @Json(name = "logout_devices")
+ val logoutDevices: Boolean? = null
) {
companion object {
- fun create(clientSecret: String, sid: String, newPassword: String): ResetPasswordMailConfirmed {
+ fun create(clientSecret: String, sid: String, newPassword: String, logoutDevices: Boolean?): ResetPasswordMailConfirmed {
return ResetPasswordMailConfirmed(
auth = AuthParams.createForResetPassword(clientSecret, sid),
- newPassword = newPassword
+ newPassword = newPassword,
+ logoutDevices = logoutDevices
)
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/AddThreePidRegistrationParams.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/AddThreePidRegistrationParams.kt
index 2f05864d3b..f0cb6ebd6d 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/AddThreePidRegistrationParams.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/AddThreePidRegistrationParams.kt
@@ -84,7 +84,7 @@ internal data class AddThreePidRegistrationParams(
companion object {
fun from(params: RegisterAddThreePidTask.Params): AddThreePidRegistrationParams {
return when (params.threePid) {
- is RegisterThreePid.Email -> AddThreePidRegistrationParams(
+ is RegisterThreePid.Email -> AddThreePidRegistrationParams(
email = params.threePid.email,
clientSecret = params.clientSecret,
sendAttempt = params.sendAttempt
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/DefaultRegistrationWizard.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/DefaultRegistrationWizard.kt
index b45c4e87f0..46ebbb7b71 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/DefaultRegistrationWizard.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/DefaultRegistrationWizard.kt
@@ -17,6 +17,7 @@
package org.matrix.android.sdk.internal.auth.registration
import kotlinx.coroutines.delay
+import org.matrix.android.sdk.api.auth.LoginType
import org.matrix.android.sdk.api.auth.data.Credentials
import org.matrix.android.sdk.api.auth.data.LoginFlowTypes
import org.matrix.android.sdk.api.auth.registration.RegisterThreePid
@@ -51,12 +52,12 @@ internal class DefaultRegistrationWizard(
override fun getCurrentThreePid(): String? {
return when (val threePid = pendingSessionData.currentThreePidData?.threePid) {
- is RegisterThreePid.Email -> threePid.email
+ is RegisterThreePid.Email -> threePid.email
is RegisterThreePid.Msisdn -> {
// Take formatted msisdn if provided by the server
pendingSessionData.currentThreePidData?.addThreePidRegistrationResponse?.formattedMsisdn?.takeIf { it.isNotBlank() } ?: threePid.msisdn
}
- null -> null
+ null -> null
}
}
@@ -64,7 +65,7 @@ internal class DefaultRegistrationWizard(
override suspend fun getRegistrationFlow(): RegistrationResult {
val params = RegistrationParams()
- return performRegistrationRequest(params)
+ return performRegistrationRequest(params, LoginType.PASSWORD)
}
override suspend fun createAccount(
@@ -77,7 +78,7 @@ internal class DefaultRegistrationWizard(
password = password,
initialDeviceDisplayName = initialDeviceDisplayName
)
- return performRegistrationRequest(params)
+ return performRegistrationRequest(params, LoginType.PASSWORD)
.also {
pendingSessionData = pendingSessionData.copy(isRegistrationStarted = true)
.also { pendingSessionStore.savePendingSessionData(it) }
@@ -89,7 +90,7 @@ internal class DefaultRegistrationWizard(
?: throw IllegalStateException("developer error, call createAccount() method first")
val params = RegistrationParams(auth = AuthParams.createForCaptcha(safeSession, response))
- return performRegistrationRequest(params)
+ return performRegistrationRequest(params, LoginType.PASSWORD)
}
override suspend fun acceptTerms(): RegistrationResult {
@@ -97,7 +98,7 @@ internal class DefaultRegistrationWizard(
?: throw IllegalStateException("developer error, call createAccount() method first")
val params = RegistrationParams(auth = AuthParams(type = LoginFlowTypes.TERMS, session = safeSession))
- return performRegistrationRequest(params)
+ return performRegistrationRequest(params, LoginType.PASSWORD)
}
override suspend fun addThreePid(threePid: RegisterThreePid): RegistrationResult {
@@ -151,14 +152,14 @@ internal class DefaultRegistrationWizard(
.also { pendingSessionStore.savePendingSessionData(it) }
// and send the sid a first time
- return performRegistrationRequest(params)
+ return performRegistrationRequest(params, LoginType.PASSWORD)
}
override suspend fun checkIfEmailHasBeenValidated(delayMillis: Long): RegistrationResult {
val safeParam = pendingSessionData.currentThreePidData?.registrationParams
?: throw IllegalStateException("developer error, no pending three pid")
- return performRegistrationRequest(safeParam, delayMillis)
+ return performRegistrationRequest(safeParam, LoginType.PASSWORD, delayMillis)
}
override suspend fun handleValidateThreePid(code: String): RegistrationResult {
@@ -179,7 +180,7 @@ internal class DefaultRegistrationWizard(
if (validationResponse.isSuccess()) {
// The entered code is correct
// Same than validate email
- return performRegistrationRequest(registrationParams, 3_000)
+ return performRegistrationRequest(registrationParams, LoginType.PASSWORD, 3_000)
} else {
// The code is not correct
throw Failure.SuccessError
@@ -191,7 +192,7 @@ internal class DefaultRegistrationWizard(
?: throw IllegalStateException("developer error, call createAccount() method first")
val params = RegistrationParams(auth = AuthParams(type = LoginFlowTypes.DUMMY, session = safeSession))
- return performRegistrationRequest(params)
+ return performRegistrationRequest(params, LoginType.PASSWORD)
}
override suspend fun registrationCustom(
@@ -204,25 +205,28 @@ internal class DefaultRegistrationWizard(
mutableParams["session"] = safeSession
val params = RegistrationCustomParams(auth = mutableParams)
- return performRegistrationOtherRequest(params)
+ return performRegistrationOtherRequest(LoginType.CUSTOM, params)
}
private suspend fun performRegistrationRequest(
registrationParams: RegistrationParams,
+ loginType: LoginType,
delayMillis: Long = 0
): RegistrationResult {
delay(delayMillis)
- return register { registerTask.execute(RegisterTask.Params(registrationParams)) }
+ return register(loginType) { registerTask.execute(RegisterTask.Params(registrationParams)) }
}
private suspend fun performRegistrationOtherRequest(
- registrationCustomParams: RegistrationCustomParams
+ loginType: LoginType,
+ registrationCustomParams: RegistrationCustomParams,
): RegistrationResult {
- return register { registerCustomTask.execute(RegisterCustomTask.Params(registrationCustomParams)) }
+ return register(loginType) { registerCustomTask.execute(RegisterCustomTask.Params(registrationCustomParams)) }
}
private suspend fun register(
- execute: suspend () -> Credentials
+ loginType: LoginType,
+ execute: suspend () -> Credentials,
): RegistrationResult {
val credentials = try {
execute.invoke()
@@ -237,8 +241,7 @@ internal class DefaultRegistrationWizard(
}
}
- val session =
- sessionCreator.createSession(credentials, pendingSessionData.homeServerConnectionConfig)
+ val session = sessionCreator.createSession(credentials, pendingSessionData.homeServerConnectionConfig, loginType)
return RegistrationResult.Success(session)
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/RegisterAddThreePidTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/RegisterAddThreePidTask.kt
index 54a8ba0e6c..b84ed61361 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/RegisterAddThreePidTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/RegisterAddThreePidTask.kt
@@ -41,7 +41,7 @@ internal class DefaultRegisterAddThreePidTask(
private fun RegisterThreePid.toPath(): String {
return when (this) {
- is RegisterThreePid.Email -> "email"
+ is RegisterThreePid.Email -> "email"
is RegisterThreePid.Msisdn -> "msisdn"
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/ThreePidData.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/ThreePidData.kt
index 70615809d8..dde0a44ea0 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/ThreePidData.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/ThreePidData.kt
@@ -46,7 +46,7 @@ internal data class ThreePidData(
registrationParams: RegistrationParams
): ThreePidData {
return when (threePid) {
- is RegisterThreePid.Email ->
+ is RegisterThreePid.Email ->
ThreePidData(threePid.email, "", "", addThreePidRegistrationResponse, registrationParams)
is RegisterThreePid.Msisdn ->
ThreePidData("", threePid.msisdn, threePid.countryCode, addThreePidRegistrationResponse, registrationParams)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/version/HomeServerVersion.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/version/HomeServerVersion.kt
index 239adfdbbd..75639c6a21 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/version/HomeServerVersion.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/version/HomeServerVersion.kt
@@ -35,7 +35,7 @@ internal data class HomeServerVersion(
minor < other.minor -> -1
patch > other.patch -> 1
patch < other.patch -> -1
- else -> 0
+ else -> 0
}
}
@@ -58,6 +58,7 @@ internal data class HomeServerVersion(
val r0_4_0 = HomeServerVersion(major = 0, minor = 4, patch = 0)
val r0_5_0 = HomeServerVersion(major = 0, minor = 5, patch = 0)
val r0_6_0 = HomeServerVersion(major = 0, minor = 6, patch = 0)
+ val r0_6_1 = HomeServerVersion(major = 0, minor = 6, patch = 1)
val v1_3_0 = HomeServerVersion(major = 1, minor = 3, patch = 0)
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/version/Versions.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/version/Versions.kt
index cee4b12138..915b25134b 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/version/Versions.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/version/Versions.kt
@@ -111,6 +111,15 @@ private fun Versions.doesServerSeparatesAddAndBind(): Boolean {
unstableFeatures?.get(FEATURE_SEPARATE_ADD_AND_BIND) ?: false
}
+/**
+ * Indicate if the server supports MSC2457 `logout_devices` parameter when setting a new password.
+ *
+ * @return true if logout_devices is supported
+ */
+internal fun Versions.doesServerSupportLogoutDevices(): Boolean {
+ return getMaxVersion() >= HomeServerVersion.r0_6_1
+}
+
private fun Versions.getMaxVersion(): HomeServerVersion {
return supportedVersions
?.mapNotNull { HomeServerVersion.parse(it) }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt
index a5afe3f81d..35c066dea8 100755
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt
@@ -71,6 +71,7 @@ import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibility
import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibilityContent
import org.matrix.android.sdk.api.session.room.model.RoomMemberContent
+import org.matrix.android.sdk.api.session.room.model.shouldShareHistory
import org.matrix.android.sdk.api.session.sync.model.SyncResponse
import org.matrix.android.sdk.internal.crypto.actions.MegolmSessionDataImporter
import org.matrix.android.sdk.internal.crypto.actions.SetDeviceVerificationAction
@@ -81,6 +82,7 @@ import org.matrix.android.sdk.internal.crypto.algorithms.olm.MXOlmEncryptionFact
import org.matrix.android.sdk.internal.crypto.crosssigning.DefaultCrossSigningService
import org.matrix.android.sdk.internal.crypto.keysbackup.DefaultKeysBackupService
import org.matrix.android.sdk.internal.crypto.model.MXKey.Companion.KEY_SIGNED_CURVE_25519_TYPE
+import org.matrix.android.sdk.internal.crypto.model.SessionInfo
import org.matrix.android.sdk.internal.crypto.model.toRest
import org.matrix.android.sdk.internal.crypto.repository.WarnOnUnknownDeviceRepository
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
@@ -188,8 +190,8 @@ internal class DefaultCryptoService @Inject constructor(
fun onStateEvent(roomId: String, event: Event) {
when (event.type) {
- EventType.STATE_ROOM_ENCRYPTION -> onRoomEncryptionEvent(roomId, event)
- EventType.STATE_ROOM_MEMBER -> onRoomMembershipEvent(roomId, event)
+ EventType.STATE_ROOM_ENCRYPTION -> onRoomEncryptionEvent(roomId, event)
+ EventType.STATE_ROOM_MEMBER -> onRoomMembershipEvent(roomId, event)
EventType.STATE_ROOM_HISTORY_VISIBILITY -> onRoomHistoryVisibilityEvent(roomId, event)
}
}
@@ -198,8 +200,8 @@ internal class DefaultCryptoService @Inject constructor(
// handle state events
if (event.isStateEvent()) {
when (event.type) {
- EventType.STATE_ROOM_ENCRYPTION -> onRoomEncryptionEvent(roomId, event)
- EventType.STATE_ROOM_MEMBER -> onRoomMembershipEvent(roomId, event)
+ EventType.STATE_ROOM_ENCRYPTION -> onRoomEncryptionEvent(roomId, event)
+ EventType.STATE_ROOM_MEMBER -> onRoomMembershipEvent(roomId, event)
EventType.STATE_ROOM_HISTORY_VISIBILITY -> onRoomHistoryVisibilityEvent(roomId, event)
}
}
@@ -620,8 +622,8 @@ internal class DefaultCryptoService @Inject constructor(
val alg: IMXEncrypting? = when (algorithm) {
MXCRYPTO_ALGORITHM_MEGOLM -> megolmEncryptionFactory.create(roomId)
- MXCRYPTO_ALGORITHM_OLM -> olmEncryptionFactory.create(roomId)
- else -> null
+ MXCRYPTO_ALGORITHM_OLM -> olmEncryptionFactory.create(roomId)
+ else -> null
}
if (alg != null) {
@@ -800,10 +802,10 @@ internal class DefaultCryptoService @Inject constructor(
// Keys are imported directly, not waiting for end of sync
onRoomKeyEvent(event)
}
- EventType.REQUEST_SECRET -> {
+ EventType.REQUEST_SECRET -> {
secretShareManager.handleSecretRequest(event)
}
- EventType.ROOM_KEY_REQUEST -> {
+ EventType.ROOM_KEY_REQUEST -> {
event.getClearContent().toModel()?.let { req ->
// We'll always get these because we send room key requests to
// '*' (ie. 'all devices') which includes the sending device,
@@ -815,13 +817,13 @@ internal class DefaultCryptoService @Inject constructor(
}
}
}
- EventType.SEND_SECRET -> {
+ EventType.SEND_SECRET -> {
onSecretSendReceived(event)
}
- EventType.ROOM_KEY_WITHHELD -> {
+ in EventType.ROOM_KEY_WITHHELD.values -> {
onKeyWithHeldReceived(event)
}
- else -> {
+ else -> {
// ignore
}
}
@@ -867,7 +869,7 @@ internal class DefaultCryptoService @Inject constructor(
senderKey = withHeldContent.senderKey,
fromDevice = withHeldContent.fromDevice,
event = Event(
- type = EventType.ROOM_KEY_WITHHELD,
+ type = EventType.ROOM_KEY_WITHHELD.stable,
senderId = senderId,
content = event.getClearContent()
)
@@ -888,7 +890,7 @@ internal class DefaultCryptoService @Inject constructor(
secretValue: String
): Boolean {
return when (secretName) {
- MASTER_KEY_SSSS_NAME -> {
+ MASTER_KEY_SSSS_NAME -> {
crossSigningService.onSecretMSKGossip(secretValue)
true
}
@@ -904,7 +906,7 @@ internal class DefaultCryptoService @Inject constructor(
keysBackupService.onSecretKeyGossip(secretValue)
true
}
- else -> false
+ else -> false
}
}
@@ -963,8 +965,12 @@ internal class DefaultCryptoService @Inject constructor(
private fun onRoomHistoryVisibilityEvent(roomId: String, event: Event) {
if (!event.isStateEvent()) return
val eventContent = event.content.toModel()
- eventContent?.historyVisibility?.let {
- cryptoStore.setShouldEncryptForInvitedMembers(roomId, it != RoomHistoryVisibility.JOINED)
+ val historyVisibility = eventContent?.historyVisibility
+ if (historyVisibility == null) {
+ cryptoStore.setShouldShareHistory(roomId, false)
+ } else {
+ cryptoStore.setShouldEncryptForInvitedMembers(roomId, historyVisibility != RoomHistoryVisibility.JOINED)
+ cryptoStore.setShouldShareHistory(roomId, historyVisibility.shouldShareHistory())
}
}
@@ -1111,6 +1117,10 @@ internal class DefaultCryptoService @Inject constructor(
override fun isKeyGossipingEnabled() = cryptoStore.isKeyGossipingEnabled()
+ override fun isShareKeysOnInviteEnabled() = cryptoStore.isShareKeysOnInviteEnabled()
+
+ override fun enableShareKeyOnInvite(enable: Boolean) = cryptoStore.enableShareKeyOnInvite(enable)
+
/**
* Tells whether the client should ever send encrypted messages to unverified devices.
* The default value is false.
@@ -1298,10 +1308,6 @@ internal class DefaultCryptoService @Inject constructor(
return cryptoStore.getWithHeldMegolmSession(roomId, sessionId)
}
- override fun logDbUsageInfo() {
- cryptoStore.logDbUsageInfo()
- }
-
override fun prepareToEncrypt(roomId: String, callback: MatrixCallback) {
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
Timber.tag(loggerTag.value).d("prepareToEncrypt() roomId:$roomId Check room members up to date")
@@ -1339,6 +1345,30 @@ internal class DefaultCryptoService @Inject constructor(
}
}
+ override suspend fun sendSharedHistoryKeys(roomId: String, userId: String, sessionInfoSet: Set?) {
+ deviceListManager.downloadKeys(listOf(userId), false)
+ val userDevices = cryptoStore.getUserDeviceList(userId)
+ val sessionToShare = sessionInfoSet.orEmpty().mapNotNull { sessionInfo ->
+ // Get inbound session from sessionId and sessionKey
+ withContext(coroutineDispatchers.crypto) {
+ olmDevice.getInboundGroupSession(
+ sessionId = sessionInfo.sessionId,
+ senderKey = sessionInfo.senderKey,
+ roomId = roomId
+ ).takeIf { it.wrapper.sessionData.sharedHistory }
+ }
+ }
+
+ userDevices?.forEach { deviceInfo ->
+ // Lets share the provided inbound sessions for every user device
+ sessionToShare.forEach { inboundGroupSession ->
+ val encryptor = roomEncryptorsStore.get(roomId)
+ encryptor?.shareHistoryKeysWithDevice(inboundGroupSession, deviceInfo)
+ Timber.i("## CRYPTO | Sharing inbound session")
+ }
+ }
+ }
+
/* ==========================================================================================
* For test only
* ========================================================================================== */
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DeviceListManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DeviceListManager.kt
index 18b815b3d8..4f3900adb9 100755
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DeviceListManager.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DeviceListManager.kt
@@ -231,8 +231,8 @@ internal class DeviceListManager @Inject constructor(
for ((k, value) in failures) {
val statusCode = when (val status = value["status"]) {
is Double -> status.toInt()
- is Int -> status.toInt()
- else -> 0
+ is Int -> status.toInt()
+ else -> 0
}
if (statusCode == 503) {
synchronized(notReadyToRetryHS) {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/EventDecryptor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/EventDecryptor.kt
index c1d04eb22b..bc3309132a 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/EventDecryptor.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/EventDecryptor.kt
@@ -18,6 +18,8 @@ package org.matrix.android.sdk.internal.crypto
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
+import kotlinx.coroutines.sync.Mutex
+import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext
import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
@@ -68,6 +70,7 @@ internal class EventDecryptor @Inject constructor(
val senderKey: String?
)
+ private val wedgedMutex = Mutex()
private val wedgedDevices = mutableListOf()
/**
@@ -151,11 +154,13 @@ internal class EventDecryptor @Inject constructor(
}
}
- private fun markOlmSessionForUnwedging(senderId: String, senderKey: String) {
- val info = WedgedDeviceInfo(senderId, senderKey)
- if (!wedgedDevices.contains(info)) {
- Timber.tag(loggerTag.value).d("Marking device from $senderId key:$senderKey as wedged")
- wedgedDevices.add(info)
+ private suspend fun markOlmSessionForUnwedging(senderId: String, senderKey: String) {
+ wedgedMutex.withLock {
+ val info = WedgedDeviceInfo(senderId, senderKey)
+ if (!wedgedDevices.contains(info)) {
+ Timber.tag(loggerTag.value).d("Marking device from $senderId key:$senderKey as wedged")
+ wedgedDevices.add(info)
+ }
}
}
@@ -167,15 +172,17 @@ internal class EventDecryptor @Inject constructor(
Timber.tag(loggerTag.value).v("Unwedging: ${wedgedDevices.size} are wedged")
// get the one that should be retried according to rate limit
val now = clock.epochMillis()
- val toUnwedge = wedgedDevices.filter {
- val lastForcedDate = lastNewSessionForcedDates[it] ?: 0
- if (now - lastForcedDate < DefaultCryptoService.CRYPTO_MIN_FORCE_SESSION_PERIOD_MILLIS) {
- Timber.tag(loggerTag.value).d("Unwedging, New session for $it already forced with device at $lastForcedDate")
- return@filter false
+ val toUnwedge = wedgedMutex.withLock {
+ wedgedDevices.filter {
+ val lastForcedDate = lastNewSessionForcedDates[it] ?: 0
+ if (now - lastForcedDate < DefaultCryptoService.CRYPTO_MIN_FORCE_SESSION_PERIOD_MILLIS) {
+ Timber.tag(loggerTag.value).d("Unwedging, New session for $it already forced with device at $lastForcedDate")
+ return@filter false
+ }
+ // let's already mark that we tried now
+ lastNewSessionForcedDates[it] = now
+ true
}
- // let's already mark that we tried now
- lastNewSessionForcedDates[it] = now
- true
}
if (toUnwedge.isEmpty()) {
@@ -230,6 +237,15 @@ internal class EventDecryptor @Inject constructor(
withContext(coroutineDispatchers.io) {
sendToDeviceTask.executeRetry(sendToDeviceParams, remainingRetry = SEND_TO_DEVICE_RETRY_COUNT)
}
+
+ deviceList.values.flatten().forEach { deviceInfo ->
+ wedgedMutex.withLock {
+ wedgedDevices.removeAll {
+ it.senderKey == deviceInfo.identityKey() &&
+ it.userId == deviceInfo.userId
+ }
+ }
+ }
} catch (failure: Throwable) {
deviceList.flatMap { it.value }.joinToString { it.shortDebugString() }.let {
Timber.tag(loggerTag.value).e(failure, "## Failed to unwedge devices: $it}")
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/InboundGroupSessionStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/InboundGroupSessionStore.kt
index e4d322cadd..39dfb72149 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/InboundGroupSessionStore.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/InboundGroupSessionStore.kt
@@ -21,17 +21,14 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Mutex
import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
-import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.logger.LoggerTag
-import org.matrix.android.sdk.internal.crypto.model.OlmInboundGroupSessionWrapper2
+import org.matrix.android.sdk.internal.crypto.model.MXInboundMegolmSessionWrapper
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
import timber.log.Timber
-import java.util.Timer
-import java.util.TimerTask
import javax.inject.Inject
internal data class InboundGroupSessionHolder(
- val wrapper: OlmInboundGroupSessionWrapper2,
+ val wrapper: MXInboundMegolmSessionWrapper,
val mutex: Mutex = Mutex()
)
@@ -57,18 +54,13 @@ internal class InboundGroupSessionStore @Inject constructor(
if (oldValue != null) {
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
Timber.tag(loggerTag.value).v("## Inbound: entryRemoved ${oldValue.wrapper.roomId}-${oldValue.wrapper.senderKey}")
- store.storeInboundGroupSessions(listOf(oldValue).map { it.wrapper })
- oldValue.wrapper.olmInboundGroupSession?.releaseSession()
+ // store.storeInboundGroupSessions(listOf(oldValue).map { it.wrapper })
+ oldValue.wrapper.session.releaseSession()
}
}
}
}
- private val timer = Timer()
- private var timerTask: TimerTask? = null
-
- private val dirtySession = mutableListOf()
-
@Synchronized
fun clear() {
sessionCache.evictAll()
@@ -90,12 +82,11 @@ internal class InboundGroupSessionStore @Inject constructor(
@Synchronized
fun replaceGroupSession(old: InboundGroupSessionHolder, new: InboundGroupSessionHolder, sessionId: String, senderKey: String) {
Timber.tag(loggerTag.value).v("## Replacing outdated session ${old.wrapper.roomId}-${old.wrapper.senderKey}")
- dirtySession.remove(old.wrapper)
store.removeInboundGroupSession(sessionId, senderKey)
sessionCache.remove(CacheKey(sessionId, senderKey))
// release removed session
- old.wrapper.olmInboundGroupSession?.releaseSession()
+ old.wrapper.session.releaseSession()
internalStoreGroupSession(new, sessionId, senderKey)
}
@@ -107,33 +98,14 @@ internal class InboundGroupSessionStore @Inject constructor(
private fun internalStoreGroupSession(holder: InboundGroupSessionHolder, sessionId: String, senderKey: String) {
Timber.tag(loggerTag.value).v("## Inbound: getInboundGroupSession mark as dirty ${holder.wrapper.roomId}-${holder.wrapper.senderKey}")
- // We want to batch this a bit for performances
- dirtySession.add(holder.wrapper)
if (sessionCache[CacheKey(sessionId, senderKey)] == null) {
// first time seen, put it in memory cache while waiting for batch insert
// If it's already known, no need to update cache it's already there
sessionCache.put(CacheKey(sessionId, senderKey), holder)
}
-
- timerTask?.cancel()
- timerTask = object : TimerTask() {
- override fun run() {
- batchSave()
- }
- }
- timer.schedule(timerTask!!, 300)
- }
-
- @Synchronized
- private fun batchSave() {
- val toSave = mutableListOf().apply { addAll(dirtySession) }
- dirtySession.clear()
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
- Timber.tag(loggerTag.value).v("## Inbound: getInboundGroupSession batching save of ${toSave.size}")
- tryOrNull {
- store.storeInboundGroupSessions(toSave)
- }
+ store.storeInboundGroupSessions(listOf(holder.wrapper))
}
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/IncomingKeyRequestManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/IncomingKeyRequestManager.kt
index f8baab7c06..729b4481e4 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/IncomingKeyRequestManager.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/IncomingKeyRequestManager.kt
@@ -135,7 +135,7 @@ internal class IncomingKeyRequestManager @Inject constructor(
// just add to the buffer
incomingRequestBuffer.add(validMegolmRequest)
}
- MegolmRequestAction.Cancel -> {
+ MegolmRequestAction.Cancel -> {
// ignore, we can't cancel as it's not known (probably already processed)
// still notify app layer if it was passed up previously
IncomingRoomKeyRequest.fromRestRequest(senderId, request, clock)?.let { iReq ->
@@ -159,7 +159,7 @@ internal class IncomingKeyRequestManager @Inject constructor(
MegolmRequestAction.Request -> {
// it's already in buffer, nop keep existing
}
- MegolmRequestAction.Cancel -> {
+ MegolmRequestAction.Cancel -> {
// discard the request in buffer
incomingRequestBuffer.remove(existing)
outgoingRequestScope.launch(coroutineDispatchers.computation) {
@@ -315,7 +315,7 @@ internal class IncomingKeyRequestManager @Inject constructor(
)
val params = SendToDeviceTask.Params(
- EventType.ROOM_KEY_WITHHELD,
+ EventType.ROOM_KEY_WITHHELD.stable,
MXUsersDevicesMap().apply {
setObject(request.requestingUserId, request.requestingDeviceId, withHeldContent)
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MXCryptoAlgorithms.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MXCryptoAlgorithms.kt
index 5a5ee9e696..14b0e8e125 100755
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MXCryptoAlgorithms.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MXCryptoAlgorithms.kt
@@ -32,7 +32,7 @@ internal object MXCryptoAlgorithms {
return when (algorithm) {
MXCRYPTO_ALGORITHM_MEGOLM,
MXCRYPTO_ALGORITHM_OLM -> true
- else -> false
+ else -> false
}
}
@@ -47,7 +47,7 @@ internal object MXCryptoAlgorithms {
return when (algorithm) {
MXCRYPTO_ALGORITHM_MEGOLM,
MXCRYPTO_ALGORITHM_OLM -> true
- else -> false
+ else -> false
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MXOlmDevice.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MXOlmDevice.kt
index 24b6fd166f..96ccba51dc 100755
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MXOlmDevice.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MXOlmDevice.kt
@@ -27,7 +27,8 @@ import org.matrix.android.sdk.api.util.JSON_DICT_PARAMETERIZED_TYPE
import org.matrix.android.sdk.api.util.JsonDict
import org.matrix.android.sdk.internal.crypto.algorithms.megolm.MXOutboundSessionInfo
import org.matrix.android.sdk.internal.crypto.algorithms.megolm.SharedWithHelper
-import org.matrix.android.sdk.internal.crypto.model.OlmInboundGroupSessionWrapper2
+import org.matrix.android.sdk.internal.crypto.model.InboundGroupSessionData
+import org.matrix.android.sdk.internal.crypto.model.MXInboundMegolmSessionWrapper
import org.matrix.android.sdk.internal.crypto.model.OlmSessionWrapper
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
import org.matrix.android.sdk.internal.di.MoshiProvider
@@ -38,6 +39,7 @@ import org.matrix.android.sdk.internal.util.convertToUTF8
import org.matrix.android.sdk.internal.util.time.Clock
import org.matrix.olm.OlmAccount
import org.matrix.olm.OlmException
+import org.matrix.olm.OlmInboundGroupSession
import org.matrix.olm.OlmMessage
import org.matrix.olm.OlmOutboundGroupSession
import org.matrix.olm.OlmSession
@@ -514,8 +516,9 @@ internal class MXOlmDevice @Inject constructor(
return MXOutboundSessionInfo(
sessionId = sessionId,
sharedWithHelper = SharedWithHelper(roomId, sessionId, store),
- clock,
- restoredOutboundGroupSession.creationTime
+ clock = clock,
+ creationTime = restoredOutboundGroupSession.creationTime,
+ sharedHistory = restoredOutboundGroupSession.sharedHistory
)
}
return null
@@ -598,6 +601,7 @@ internal class MXOlmDevice @Inject constructor(
* @param forwardingCurve25519KeyChain Devices involved in forwarding this session to us.
* @param keysClaimed Other keys the sender claims.
* @param exportFormat true if the megolm keys are in export format
+ * @param sharedHistory MSC3061, this key is sharable on invite
* @return true if the operation succeeds.
*/
fun addInboundGroupSession(
@@ -607,31 +611,39 @@ internal class MXOlmDevice @Inject constructor(
senderKey: String,
forwardingCurve25519KeyChain: List,
keysClaimed: Map,
- exportFormat: Boolean
+ exportFormat: Boolean,
+ sharedHistory: Boolean
): AddSessionResult {
- val candidateSession = OlmInboundGroupSessionWrapper2(sessionKey, exportFormat)
+ val candidateSession = tryOrNull("Failed to create inbound session in room $roomId") {
+ if (exportFormat) {
+ OlmInboundGroupSession.importSession(sessionKey)
+ } else {
+ OlmInboundGroupSession(sessionKey)
+ }
+ }
+
val existingSessionHolder = tryOrNull { getInboundGroupSession(sessionId, senderKey, roomId) }
val existingSession = existingSessionHolder?.wrapper
// If we have an existing one we should check if the new one is not better
if (existingSession != null) {
Timber.tag(loggerTag.value).d("## addInboundGroupSession() check if known session is better than candidate session")
try {
- val existingFirstKnown = existingSession.firstKnownIndex ?: return AddSessionResult.NotImported.also {
+ val existingFirstKnown = tryOrNull { existingSession.session.firstKnownIndex } ?: return AddSessionResult.NotImported.also {
// This is quite unexpected, could throw if native was released?
Timber.tag(loggerTag.value).e("## addInboundGroupSession() null firstKnownIndex on existing session")
- candidateSession.olmInboundGroupSession?.releaseSession()
+ candidateSession?.releaseSession()
// Probably should discard it?
}
- val newKnownFirstIndex = candidateSession.firstKnownIndex
+ val newKnownFirstIndex = tryOrNull("Failed to get candidate first known index") { candidateSession?.firstKnownIndex }
// If our existing session is better we keep it
if (newKnownFirstIndex != null && existingFirstKnown <= newKnownFirstIndex) {
Timber.tag(loggerTag.value).d("## addInboundGroupSession() : ignore session our is better $senderKey/$sessionId")
- candidateSession.olmInboundGroupSession?.releaseSession()
+ candidateSession?.releaseSession()
return AddSessionResult.NotImportedHigherIndex(newKnownFirstIndex.toInt())
}
} catch (failure: Throwable) {
Timber.tag(loggerTag.value).e("## addInboundGroupSession() Failed to add inbound: ${failure.localizedMessage}")
- candidateSession.olmInboundGroupSession?.releaseSession()
+ candidateSession?.releaseSession()
return AddSessionResult.NotImported
}
}
@@ -639,36 +651,42 @@ internal class MXOlmDevice @Inject constructor(
Timber.tag(loggerTag.value).d("## addInboundGroupSession() : Candidate session should be added $senderKey/$sessionId")
// sanity check on the new session
- val candidateOlmInboundSession = candidateSession.olmInboundGroupSession
- if (null == candidateOlmInboundSession) {
+ if (null == candidateSession) {
Timber.tag(loggerTag.value).e("## addInboundGroupSession : invalid session ")
return AddSessionResult.NotImported
}
try {
- if (candidateOlmInboundSession.sessionIdentifier() != sessionId) {
+ if (candidateSession.sessionIdentifier() != sessionId) {
Timber.tag(loggerTag.value).e("## addInboundGroupSession : ERROR: Mismatched group session ID from senderKey: $senderKey")
- candidateOlmInboundSession.releaseSession()
+ candidateSession.releaseSession()
return AddSessionResult.NotImported
}
} catch (e: Throwable) {
- candidateOlmInboundSession.releaseSession()
+ candidateSession.releaseSession()
Timber.tag(loggerTag.value).e(e, "## addInboundGroupSession : sessionIdentifier() failed")
return AddSessionResult.NotImported
}
- candidateSession.senderKey = senderKey
- candidateSession.roomId = roomId
- candidateSession.keysClaimed = keysClaimed
- candidateSession.forwardingCurve25519KeyChain = forwardingCurve25519KeyChain
+ val candidateSessionData = InboundGroupSessionData(
+ senderKey = senderKey,
+ roomId = roomId,
+ keysClaimed = keysClaimed,
+ forwardingCurve25519KeyChain = forwardingCurve25519KeyChain,
+ sharedHistory = sharedHistory,
+ )
+ val wrapper = MXInboundMegolmSessionWrapper(
+ candidateSession,
+ candidateSessionData
+ )
if (existingSession != null) {
- inboundGroupSessionStore.replaceGroupSession(existingSessionHolder, InboundGroupSessionHolder(candidateSession), sessionId, senderKey)
+ inboundGroupSessionStore.replaceGroupSession(existingSessionHolder, InboundGroupSessionHolder(wrapper), sessionId, senderKey)
} else {
- inboundGroupSessionStore.storeInBoundGroupSession(InboundGroupSessionHolder(candidateSession), sessionId, senderKey)
+ inboundGroupSessionStore.storeInBoundGroupSession(InboundGroupSessionHolder(wrapper), sessionId, senderKey)
}
- return AddSessionResult.Imported(candidateSession.firstKnownIndex?.toInt() ?: 0)
+ return AddSessionResult.Imported(candidateSession.firstKnownIndex.toInt())
}
/**
@@ -677,41 +695,22 @@ internal class MXOlmDevice @Inject constructor(
* @param megolmSessionsData the megolm sessions data
* @return the successfully imported sessions.
*/
- fun importInboundGroupSessions(megolmSessionsData: List): List {
- val sessions = ArrayList(megolmSessionsData.size)
+ fun importInboundGroupSessions(megolmSessionsData: List): List {
+ val sessions = ArrayList(megolmSessionsData.size)
for (megolmSessionData in megolmSessionsData) {
val sessionId = megolmSessionData.sessionId ?: continue
val senderKey = megolmSessionData.senderKey ?: continue
val roomId = megolmSessionData.roomId
- var candidateSessionToImport: OlmInboundGroupSessionWrapper2? = null
-
- try {
- candidateSessionToImport = OlmInboundGroupSessionWrapper2(megolmSessionData)
- } catch (e: Exception) {
- Timber.tag(loggerTag.value).e(e, "## importInboundGroupSession() : Update for megolm session $senderKey/$sessionId")
- }
-
- // sanity check
- if (candidateSessionToImport?.olmInboundGroupSession == null) {
- Timber.tag(loggerTag.value).e("## importInboundGroupSession : invalid session")
- continue
- }
-
- val candidateOlmInboundGroupSession = candidateSessionToImport.olmInboundGroupSession
- try {
- if (candidateOlmInboundGroupSession?.sessionIdentifier() != sessionId) {
- Timber.tag(loggerTag.value).e("## importInboundGroupSession : ERROR: Mismatched group session ID from senderKey: $senderKey")
- candidateOlmInboundGroupSession?.releaseSession()
- continue
- }
- } catch (e: Exception) {
- Timber.tag(loggerTag.value).e(e, "## importInboundGroupSession : sessionIdentifier() failed")
- candidateOlmInboundGroupSession?.releaseSession()
+ val candidateSessionToImport = try {
+ MXInboundMegolmSessionWrapper.newFromMegolmData(megolmSessionData, true)
+ } catch (e: Throwable) {
+ Timber.tag(loggerTag.value).e(e, "## importInboundGroupSession() : Failed to import session $senderKey/$sessionId")
continue
}
+ val candidateOlmInboundGroupSession = candidateSessionToImport.session
val existingSessionHolder = tryOrNull { getInboundGroupSession(sessionId, senderKey, roomId) }
val existingSession = existingSessionHolder?.wrapper
@@ -721,16 +720,16 @@ internal class MXOlmDevice @Inject constructor(
sessions.add(candidateSessionToImport)
} else {
Timber.tag(loggerTag.value).e("## importInboundGroupSession() : Update for megolm session $senderKey/$sessionId")
- val existingFirstKnown = tryOrNull { existingSession.firstKnownIndex }
- val candidateFirstKnownIndex = tryOrNull { candidateSessionToImport.firstKnownIndex }
+ val existingFirstKnown = tryOrNull { existingSession.session.firstKnownIndex }
+ val candidateFirstKnownIndex = tryOrNull { candidateSessionToImport.session.firstKnownIndex }
if (existingFirstKnown == null || candidateFirstKnownIndex == null) {
// should not happen?
- candidateSessionToImport.olmInboundGroupSession?.releaseSession()
+ candidateSessionToImport.session.releaseSession()
Timber.tag(loggerTag.value)
.w("## importInboundGroupSession() : Can't check session null index $existingFirstKnown/$candidateFirstKnownIndex")
} else {
- if (existingFirstKnown <= candidateSessionToImport.firstKnownIndex!!) {
+ if (existingFirstKnown <= candidateFirstKnownIndex) {
// Ignore this, keep existing
candidateOlmInboundGroupSession.releaseSession()
} else {
@@ -774,8 +773,7 @@ internal class MXOlmDevice @Inject constructor(
): OlmDecryptionResult {
val sessionHolder = getInboundGroupSession(sessionId, senderKey, roomId)
val wrapper = sessionHolder.wrapper
- val inboundGroupSession = wrapper.olmInboundGroupSession
- ?: throw MXCryptoError.Base(MXCryptoError.ErrorType.UNABLE_TO_DECRYPT, "Session is null")
+ val inboundGroupSession = wrapper.session
if (roomId != wrapper.roomId) {
// Check that the room id matches the original one for the session. This stops
// the HS pretending a message was targeting a different room.
@@ -810,7 +808,6 @@ internal class MXOlmDevice @Inject constructor(
}
replayAttackMap[messageIndexKey] = eventId
}
- inboundGroupSessionStore.storeInBoundGroupSession(sessionHolder, sessionId, senderKey)
val payload = try {
val adapter = MoshiProvider.providesMoshi().adapter(JSON_DICT_PARAMETERIZED_TYPE)
val payloadString = convertFromUTF8(decryptResult.mDecryptedMessage)
@@ -822,9 +819,9 @@ internal class MXOlmDevice @Inject constructor(
return OlmDecryptionResult(
payload,
- wrapper.keysClaimed,
+ wrapper.sessionData.keysClaimed,
senderKey,
- wrapper.forwardingCurve25519KeyChain
+ wrapper.sessionData.forwardingCurve25519KeyChain
)
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MegolmSessionData.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MegolmSessionData.kt
index f6bc9a9148..ca0bdc8a0e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MegolmSessionData.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MegolmSessionData.kt
@@ -69,5 +69,13 @@ internal data class MegolmSessionData(
* Devices which forwarded this session to us (normally empty).
*/
@Json(name = "forwarding_curve25519_key_chain")
- val forwardingCurve25519KeyChain: List? = null
+ val forwardingCurve25519KeyChain: List? = null,
+
+ /**
+ * Flag that indicates whether or not the current inboundSession will be shared to
+ * invited users to decrypt past messages.
+ */
+ // When this feature lands in spec name = shared_history should be used
+ @Json(name = "org.matrix.msc3061.shared_history")
+ val sharedHistory: Boolean = false,
)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OutgoingKeyRequestManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OutgoingKeyRequestManager.kt
index 6e2ff5c22b..810699d933 100755
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OutgoingKeyRequestManager.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OutgoingKeyRequestManager.kt
@@ -299,19 +299,19 @@ internal class OutgoingKeyRequestManager @Inject constructor(
}
knownRequest.forEach { request ->
when (request.state) {
- OutgoingRoomKeyRequestState.UNSENT -> {
+ OutgoingRoomKeyRequestState.UNSENT -> {
if (request.fromIndex >= localKnownChainIndex) {
// we have a good index we can cancel
cryptoStore.deleteOutgoingRoomKeyRequest(request.requestId)
}
}
- OutgoingRoomKeyRequestState.SENT -> {
+ OutgoingRoomKeyRequestState.SENT -> {
// It was already sent, and index satisfied we can cancel
if (request.fromIndex >= localKnownChainIndex) {
cryptoStore.updateOutgoingRoomKeyRequestState(request.requestId, OutgoingRoomKeyRequestState.CANCELLATION_PENDING)
}
}
- OutgoingRoomKeyRequestState.CANCELLATION_PENDING -> {
+ OutgoingRoomKeyRequestState.CANCELLATION_PENDING -> {
// It is already marked to be cancelled
}
OutgoingRoomKeyRequestState.CANCELLATION_PENDING_AND_WILL_RESEND -> {
@@ -320,7 +320,7 @@ internal class OutgoingKeyRequestManager @Inject constructor(
cryptoStore.updateOutgoingRoomKeyRequestState(request.requestId, OutgoingRoomKeyRequestState.CANCELLATION_PENDING)
}
}
- OutgoingRoomKeyRequestState.SENT_THEN_CANCELED -> {
+ OutgoingRoomKeyRequestState.SENT_THEN_CANCELED -> {
// was already canceled
// if we need a better index, should we resend?
}
@@ -351,14 +351,14 @@ internal class OutgoingKeyRequestManager @Inject constructor(
val existing = cryptoStore.getOutgoingRoomKeyRequest(requestBody)
Timber.tag(loggerTag.value).v("Queueing key request exiting is ${existing?.state}")
when (existing?.state) {
- null -> {
+ null -> {
// create a new one
cryptoStore.getOrAddOutgoingRoomKeyRequest(requestBody, recipients, fromIndex)
}
- OutgoingRoomKeyRequestState.UNSENT -> {
+ OutgoingRoomKeyRequestState.UNSENT -> {
// nothing it's new or not yet handled
}
- OutgoingRoomKeyRequestState.SENT -> {
+ OutgoingRoomKeyRequestState.SENT -> {
// it was already requested
Timber.tag(loggerTag.value).d("The session ${requestBody.sessionId} is already requested")
if (force) {
@@ -371,7 +371,7 @@ internal class OutgoingKeyRequestManager @Inject constructor(
}
}
}
- OutgoingRoomKeyRequestState.CANCELLATION_PENDING -> {
+ OutgoingRoomKeyRequestState.CANCELLATION_PENDING -> {
// request is canceled only if I got the keys so what to do here...
if (force) {
cryptoStore.updateOutgoingRoomKeyRequestState(existing.requestId, OutgoingRoomKeyRequestState.CANCELLATION_PENDING_AND_WILL_RESEND)
@@ -380,7 +380,7 @@ internal class OutgoingKeyRequestManager @Inject constructor(
OutgoingRoomKeyRequestState.CANCELLATION_PENDING_AND_WILL_RESEND -> {
// It's already going to resend
}
- OutgoingRoomKeyRequestState.SENT_THEN_CANCELED -> {
+ OutgoingRoomKeyRequestState.SENT_THEN_CANCELED -> {
if (force) {
cryptoStore.deleteOutgoingRoomKeyRequest(existing.requestId)
cryptoStore.getOrAddOutgoingRoomKeyRequest(requestBody, recipients, fromIndex)
@@ -401,11 +401,11 @@ internal class OutgoingKeyRequestManager @Inject constructor(
measureTimeMillis {
toProcess.forEach {
when (it.state) {
- OutgoingRoomKeyRequestState.UNSENT -> handleUnsentRequest(it)
- OutgoingRoomKeyRequestState.CANCELLATION_PENDING -> handleRequestToCancel(it)
+ OutgoingRoomKeyRequestState.UNSENT -> handleUnsentRequest(it)
+ OutgoingRoomKeyRequestState.CANCELLATION_PENDING -> handleRequestToCancel(it)
OutgoingRoomKeyRequestState.CANCELLATION_PENDING_AND_WILL_RESEND -> handleRequestToCancelWillResend(it)
OutgoingRoomKeyRequestState.SENT_THEN_CANCELED,
- OutgoingRoomKeyRequestState.SENT -> {
+ OutgoingRoomKeyRequestState.SENT -> {
// these are filtered out
}
}
@@ -437,7 +437,10 @@ internal class OutgoingKeyRequestManager @Inject constructor(
if (perSessionBackupQueryRateLimiter.tryFromBackupIfPossible(sessionId, roomId)) {
// let's see what's the index
val knownIndex = tryOrNull {
- inboundGroupSessionStore.getInboundGroupSession(sessionId, request.requestBody?.senderKey ?: "")?.wrapper?.firstKnownIndex
+ inboundGroupSessionStore.getInboundGroupSession(sessionId, request.requestBody?.senderKey ?: "")
+ ?.wrapper
+ ?.session
+ ?.firstKnownIndex
}
if (knownIndex != null && knownIndex <= request.fromIndex) {
// we found the key in backup with good enough index, so we can just mark as cancelled, no need to send request
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/RoomDecryptorProvider.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/RoomDecryptorProvider.kt
index a80bafbe79..d37e60d289 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/RoomDecryptorProvider.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/RoomDecryptorProvider.kt
@@ -85,7 +85,7 @@ internal class RoomDecryptorProvider @Inject constructor(
}
}
}
- else -> olmDecryptionFactory.create()
+ else -> olmDecryptionFactory.create()
}
if (!roomId.isNullOrEmpty()) {
synchronized(roomDecryptors) {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/RoomEncryptorsStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/RoomEncryptorsStore.kt
index 1a8c160d9c..9f6714cc45 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/RoomEncryptorsStore.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/RoomEncryptorsStore.kt
@@ -49,8 +49,8 @@ internal class RoomEncryptorsStore @Inject constructor(
} else {
val alg: IMXEncrypting? = when (cryptoStore.getRoomAlgorithm(roomId)) {
MXCRYPTO_ALGORITHM_MEGOLM -> megolmEncryptionFactory.create(roomId)
- MXCRYPTO_ALGORITHM_OLM -> olmEncryptionFactory.create(roomId)
- else -> null
+ MXCRYPTO_ALGORITHM_OLM -> olmEncryptionFactory.create(roomId)
+ else -> null
}
alg?.let { roomEncryptors.put(roomId, it) }
return@synchronized alg
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/SecretShareManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/SecretShareManager.kt
index 6fb6914206..a79e1a8901 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/SecretShareManager.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/SecretShareManager.kt
@@ -150,14 +150,14 @@ internal class SecretShareManager @Inject constructor(
// we can share the secret
val secretValue = when (secretName) {
- MASTER_KEY_SSSS_NAME -> cryptoStore.getCrossSigningPrivateKeys()?.master
+ MASTER_KEY_SSSS_NAME -> cryptoStore.getCrossSigningPrivateKeys()?.master
SELF_SIGNING_KEY_SSSS_NAME -> cryptoStore.getCrossSigningPrivateKeys()?.selfSigned
USER_SIGNING_KEY_SSSS_NAME -> cryptoStore.getCrossSigningPrivateKeys()?.user
KEYBACKUP_SECRET_SSSS_NAME -> cryptoStore.getKeyBackupRecoveryKeyInfo()?.recoveryKey
?.let {
extractCurveKeyFromRecoveryKey(it)?.toBase64NoPadding()
}
- else -> null
+ else -> null
}
if (secretValue == null) {
Timber.tag(loggerTag.value)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/MegolmSessionDataImporter.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/MegolmSessionDataImporter.kt
index f6ab96aee6..a624b92a19 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/MegolmSessionDataImporter.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/MegolmSessionDataImporter.kt
@@ -84,8 +84,9 @@ internal class MegolmSessionDataImporter @Inject constructor(
megolmSessionData.senderKey ?: "",
tryOrNull {
olmInboundGroupSessionWrappers
- .firstOrNull { it.olmInboundGroupSession?.sessionIdentifier() == megolmSessionData.sessionId }
- ?.firstKnownIndex?.toInt()
+ .firstOrNull { it.session.sessionIdentifier() == megolmSessionData.sessionId }
+ ?.session?.firstKnownIndex
+ ?.toInt()
} ?: 0
)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/IMXEncrypting.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/IMXEncrypting.kt
index 73ce5a5004..1454f5b486 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/IMXEncrypting.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/IMXEncrypting.kt
@@ -16,7 +16,9 @@
package org.matrix.android.sdk.internal.crypto.algorithms
+import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
import org.matrix.android.sdk.api.session.events.model.Content
+import org.matrix.android.sdk.internal.crypto.InboundGroupSessionHolder
/**
* An interface for encrypting data.
@@ -32,4 +34,6 @@ internal interface IMXEncrypting {
* @return the encrypted content
*/
suspend fun encryptEventContent(eventContent: Content, eventType: String, userIds: List): Content
+
+ suspend fun shareHistoryKeysWithDevice(inboundSessionWrapper: InboundGroupSessionHolder, deviceInfo: CryptoDeviceInfo) {}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt
index 141d6f74cd..410b74e19f 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt
@@ -17,6 +17,7 @@
package org.matrix.android.sdk.internal.crypto.algorithms.megolm
import dagger.Lazy
+import org.matrix.android.sdk.api.MatrixConfiguration
import org.matrix.android.sdk.api.logger.LoggerTag
import org.matrix.android.sdk.api.session.crypto.MXCryptoError
import org.matrix.android.sdk.api.session.crypto.NewSessionListener
@@ -41,6 +42,7 @@ internal class MXMegolmDecryption(
private val olmDevice: MXOlmDevice,
private val outgoingKeyRequestManager: OutgoingKeyRequestManager,
private val cryptoStore: IMXCryptoStore,
+ private val matrixConfiguration: MatrixConfiguration,
private val liveEventManager: Lazy
) : IMXDecrypting {
@@ -240,13 +242,14 @@ internal class MXMegolmDecryption(
Timber.tag(loggerTag.value).i("onRoomKeyEvent addInboundGroupSession ${roomKeyContent.sessionId}")
val addSessionResult = olmDevice.addInboundGroupSession(
- roomKeyContent.sessionId,
- roomKeyContent.sessionKey,
- roomKeyContent.roomId,
- senderKey,
- forwardingCurve25519KeyChain,
- keysClaimed,
- exportFormat
+ sessionId = roomKeyContent.sessionId,
+ sessionKey = roomKeyContent.sessionKey,
+ roomId = roomKeyContent.roomId,
+ senderKey = senderKey,
+ forwardingCurve25519KeyChain = forwardingCurve25519KeyChain,
+ keysClaimed = keysClaimed,
+ exportFormat = exportFormat,
+ sharedHistory = roomKeyContent.getSharedKey()
)
when (addSessionResult) {
@@ -296,6 +299,14 @@ internal class MXMegolmDecryption(
}
}
+ /**
+ * Returns boolean shared key flag, if enabled with respect to matrix configuration.
+ */
+ private fun RoomKeyContent.getSharedKey(): Boolean {
+ if (!cryptoStore.isShareKeysOnInviteEnabled()) return false
+ return sharedHistory ?: false
+ }
+
/**
* Check if the some messages can be decrypted with a new session.
*
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryptionFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryptionFactory.kt
index 81a6fb28c0..38edbb7430 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryptionFactory.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryptionFactory.kt
@@ -17,6 +17,7 @@
package org.matrix.android.sdk.internal.crypto.algorithms.megolm
import dagger.Lazy
+import org.matrix.android.sdk.api.MatrixConfiguration
import org.matrix.android.sdk.internal.crypto.MXOlmDevice
import org.matrix.android.sdk.internal.crypto.OutgoingKeyRequestManager
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
@@ -27,6 +28,7 @@ internal class MXMegolmDecryptionFactory @Inject constructor(
private val olmDevice: MXOlmDevice,
private val outgoingKeyRequestManager: OutgoingKeyRequestManager,
private val cryptoStore: IMXCryptoStore,
+ private val matrixConfiguration: MatrixConfiguration,
private val eventsManager: Lazy
) {
@@ -35,6 +37,7 @@ internal class MXMegolmDecryptionFactory @Inject constructor(
olmDevice,
outgoingKeyRequestManager,
cryptoStore,
+ matrixConfiguration,
eventsManager
)
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmEncryption.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmEncryption.kt
index 7bfbae6edf..771b5f9a62 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmEncryption.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmEncryption.kt
@@ -32,6 +32,7 @@ import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.events.model.content.RoomKeyWithHeldContent
import org.matrix.android.sdk.api.session.events.model.content.WithHeldCode
import org.matrix.android.sdk.internal.crypto.DeviceListManager
+import org.matrix.android.sdk.internal.crypto.InboundGroupSessionHolder
import org.matrix.android.sdk.internal.crypto.MXOlmDevice
import org.matrix.android.sdk.internal.crypto.actions.EnsureOlmSessionsForDevicesAction
import org.matrix.android.sdk.internal.crypto.actions.MessageEncrypter
@@ -151,14 +152,27 @@ internal class MXMegolmEncryption(
"ed25519" to olmDevice.deviceEd25519Key!!
)
+ val sharedHistory = cryptoStore.shouldShareHistory(roomId)
+ Timber.tag(loggerTag.value).v("prepareNewSessionInRoom() as sharedHistory $sharedHistory")
olmDevice.addInboundGroupSession(
- sessionId!!, olmDevice.getSessionKey(sessionId)!!, roomId, olmDevice.deviceCurve25519Key!!,
- emptyList(), keysClaimedMap, false
+ sessionId = sessionId!!,
+ sessionKey = olmDevice.getSessionKey(sessionId)!!,
+ roomId = roomId,
+ senderKey = olmDevice.deviceCurve25519Key!!,
+ forwardingCurve25519KeyChain = emptyList(),
+ keysClaimed = keysClaimedMap,
+ exportFormat = false,
+ sharedHistory = sharedHistory
)
defaultKeysBackupService.maybeBackupKeys()
- return MXOutboundSessionInfo(sessionId, SharedWithHelper(roomId, sessionId, cryptoStore), clock)
+ return MXOutboundSessionInfo(
+ sessionId = sessionId,
+ sharedWithHelper = SharedWithHelper(roomId, sessionId, cryptoStore),
+ clock = clock,
+ sharedHistory = sharedHistory
+ )
}
/**
@@ -172,6 +186,8 @@ internal class MXMegolmEncryption(
if (session == null ||
// Need to make a brand new session?
session.needsRotation(sessionRotationPeriodMsgs, sessionRotationPeriodMs) ||
+ // Is there a room history visibility change since the last outboundSession
+ cryptoStore.shouldShareHistory(roomId) != session.sharedHistory ||
// Determine if we have shared with anyone we shouldn't have
session.sharedWithTooManyDevices(devicesInRoom)) {
Timber.tag(loggerTag.value).d("roomId:$roomId Starting new megolm session because we need to rotate.")
@@ -231,26 +247,29 @@ internal class MXMegolmEncryption(
/**
* Share the device keys of a an user.
*
- * @param session the session info
+ * @param sessionInfo the session info
* @param devicesByUser the devices map
*/
private suspend fun shareUserDevicesKey(
- session: MXOutboundSessionInfo,
+ sessionInfo: MXOutboundSessionInfo,
devicesByUser: Map>
) {
- val sessionKey = olmDevice.getSessionKey(session.sessionId)
- val chainIndex = olmDevice.getMessageIndex(session.sessionId)
+ val sessionKey = olmDevice.getSessionKey(sessionInfo.sessionId) ?: return Unit.also {
+ Timber.tag(loggerTag.value).v("shareUserDevicesKey() Failed to share session, failed to export")
+ }
+ val chainIndex = olmDevice.getMessageIndex(sessionInfo.sessionId)
- val submap = HashMap()
- submap["algorithm"] = MXCRYPTO_ALGORITHM_MEGOLM
- submap["room_id"] = roomId
- submap["session_id"] = session.sessionId
- submap["session_key"] = sessionKey!!
- submap["chain_index"] = chainIndex
-
- val payload = HashMap()
- payload["type"] = EventType.ROOM_KEY
- payload["content"] = submap
+ val payload = mapOf(
+ "type" to EventType.ROOM_KEY,
+ "content" to mapOf(
+ "algorithm" to MXCRYPTO_ALGORITHM_MEGOLM,
+ "room_id" to roomId,
+ "session_id" to sessionInfo.sessionId,
+ "session_key" to sessionKey,
+ "chain_index" to chainIndex,
+ "org.matrix.msc3061.shared_history" to sessionInfo.sharedHistory
+ )
+ )
var t0 = clock.epochMillis()
Timber.tag(loggerTag.value).v("shareUserDevicesKey() : starts")
@@ -292,7 +311,7 @@ internal class MXMegolmEncryption(
// for dead devices on every message.
for ((_, devicesToShareWith) in devicesByUser) {
for (deviceInfo in devicesToShareWith) {
- session.sharedWithHelper.markedSessionAsShared(deviceInfo, chainIndex)
+ sessionInfo.sharedWithHelper.markedSessionAsShared(deviceInfo, chainIndex)
// XXX is it needed to add it to the audit trail?
// For now decided that no, we are more interested by forward trail
}
@@ -300,8 +319,8 @@ internal class MXMegolmEncryption(
if (haveTargets) {
t0 = clock.epochMillis()
- Timber.tag(loggerTag.value).i("shareUserDevicesKey() ${session.sessionId} : has target")
- Timber.tag(loggerTag.value).d("sending to device room key for ${session.sessionId} to ${contentMap.toDebugString()}")
+ Timber.tag(loggerTag.value).i("shareUserDevicesKey() ${sessionInfo.sessionId} : has target")
+ Timber.tag(loggerTag.value).d("sending to device room key for ${sessionInfo.sessionId} to ${contentMap.toDebugString()}")
val sendToDeviceParams = SendToDeviceTask.Params(EventType.ENCRYPTED, contentMap)
try {
withContext(coroutineDispatchers.io) {
@@ -310,7 +329,7 @@ internal class MXMegolmEncryption(
Timber.tag(loggerTag.value).i("shareUserDevicesKey() : sendToDevice succeeds after ${clock.epochMillis() - t0} ms")
} catch (failure: Throwable) {
// What to do here...
- Timber.tag(loggerTag.value).e("shareUserDevicesKey() : Failed to share <${session.sessionId}>")
+ Timber.tag(loggerTag.value).e("shareUserDevicesKey() : Failed to share <${sessionInfo.sessionId}>")
}
} else {
Timber.tag(loggerTag.value).i("shareUserDevicesKey() : no need to share key")
@@ -320,7 +339,7 @@ internal class MXMegolmEncryption(
// XXX offload?, as they won't read the message anyhow?
notifyKeyWithHeld(
noOlmToNotify,
- session.sessionId,
+ sessionInfo.sessionId,
olmDevice.deviceCurve25519Key,
WithHeldCode.NO_OLM
)
@@ -346,7 +365,7 @@ internal class MXMegolmEncryption(
fromDevice = myDeviceId
)
val params = SendToDeviceTask.Params(
- EventType.ROOM_KEY_WITHHELD,
+ EventType.ROOM_KEY_WITHHELD.stable,
MXUsersDevicesMap().apply {
targets.forEach {
setObject(it.userId, it.deviceId, withHeldContent)
@@ -514,6 +533,51 @@ internal class MXMegolmEncryption(
}
}
+ @Throws
+ override suspend fun shareHistoryKeysWithDevice(inboundSessionWrapper: InboundGroupSessionHolder, deviceInfo: CryptoDeviceInfo) {
+ require(inboundSessionWrapper.wrapper.sessionData.sharedHistory) { "This key can't be shared" }
+ Timber.tag(loggerTag.value).i("process shareHistoryKeys for ${inboundSessionWrapper.wrapper.safeSessionId} to ${deviceInfo.shortDebugString()}")
+ val userId = deviceInfo.userId
+ val deviceId = deviceInfo.deviceId
+ val devicesByUser = mapOf(userId to listOf(deviceInfo))
+ val usersDeviceMap = try {
+ ensureOlmSessionsForDevicesAction.handle(devicesByUser)
+ } catch (failure: Throwable) {
+ Timber.tag(loggerTag.value).i(failure, "process shareHistoryKeys failed to ensure olm")
+ // process anyway?
+ null
+ }
+ val olmSessionResult = usersDeviceMap?.getObject(userId, deviceId)
+ if (olmSessionResult?.sessionId == null) {
+ Timber.tag(loggerTag.value).w("shareHistoryKeys: no session with this device, probably because there were no one-time keys")
+ return
+ }
+
+ val export = inboundSessionWrapper.mutex.withLock {
+ inboundSessionWrapper.wrapper.exportKeys()
+ } ?: return Unit.also {
+ Timber.tag(loggerTag.value).e("shareHistoryKeys: failed to export group session ${inboundSessionWrapper.wrapper.safeSessionId}")
+ }
+
+ val payloadJson = mapOf(
+ "type" to EventType.FORWARDED_ROOM_KEY,
+ "content" to export
+ )
+
+ val encodedPayload =
+ withContext(coroutineDispatchers.computation) {
+ messageEncrypter.encryptMessage(payloadJson, listOf(deviceInfo))
+ }
+ val sendToDeviceMap = MXUsersDevicesMap()
+ sendToDeviceMap.setObject(userId, deviceId, encodedPayload)
+ Timber.tag(loggerTag.value)
+ .d("shareHistoryKeys() : sending session ${inboundSessionWrapper.wrapper.safeSessionId} to ${deviceInfo.shortDebugString()}")
+ val sendToDeviceParams = SendToDeviceTask.Params(EventType.ENCRYPTED, sendToDeviceMap)
+ withContext(coroutineDispatchers.io) {
+ sendToDeviceTask.execute(sendToDeviceParams)
+ }
+ }
+
data class DeviceInRoomInfo(
val allowedDevices: MXUsersDevicesMap = MXUsersDevicesMap(),
val withHeldDevices: MXUsersDevicesMap = MXUsersDevicesMap()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXOutboundSessionInfo.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXOutboundSessionInfo.kt
index 28d925d8fd..e0caa0d9a5 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXOutboundSessionInfo.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXOutboundSessionInfo.kt
@@ -28,6 +28,7 @@ internal class MXOutboundSessionInfo(
private val clock: Clock,
// When the session was created
private val creationTime: Long = clock.epochMillis(),
+ val sharedHistory: Boolean = false
) {
// Number of times this session has been used
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmDecryption.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmDecryption.kt
index 17a44b19ff..219cadac46 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmDecryption.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmDecryption.kt
@@ -191,9 +191,9 @@ internal class MXOlmDecryption(
val messageBody = message["body"] as? String ?: return null
val messageType = when (val typeAsVoid = message["type"]) {
is Double -> typeAsVoid.toInt()
- is Int -> typeAsVoid
- is Long -> typeAsVoid.toInt()
- else -> return null
+ is Int -> typeAsVoid
+ is Long -> typeAsVoid.toInt()
+ else -> return null
}
// Try each session in turn
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/CrossSigningOlm.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/CrossSigningOlm.kt
index 4fa355cd2a..3218b99948 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/CrossSigningOlm.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/CrossSigningOlm.kt
@@ -53,13 +53,13 @@ internal class CrossSigningOlm @Inject constructor(
fun signObject(type: KeyType, strToSign: String): Map {
val myKeys = cryptoStore.getMyCrossSigningInfo()
val pubKey = when (type) {
- KeyType.SELF -> myKeys?.selfSigningKey()
- KeyType.USER -> myKeys?.userKey()
+ KeyType.SELF -> myKeys?.selfSigningKey()
+ KeyType.USER -> myKeys?.userKey()
KeyType.MASTER -> myKeys?.masterKey()
}?.unpaddedBase64PublicKey
val pkSigning = when (type) {
- KeyType.SELF -> selfSigningPkSigning
- KeyType.USER -> userPkSigning
+ KeyType.SELF -> selfSigningPkSigning
+ KeyType.USER -> userPkSigning
KeyType.MASTER -> masterPkSigning
}
if (pubKey == null || pkSigning == null) {
@@ -76,8 +76,8 @@ internal class CrossSigningOlm @Inject constructor(
?: throw NoSuchElementException("Cross Signing not configured")
val myUserID = myKeys.userId
val pubKey = when (type) {
- KeyType.SELF -> myKeys.selfSigningKey()
- KeyType.USER -> myKeys.userKey()
+ KeyType.SELF -> myKeys.selfSigningKey()
+ KeyType.USER -> myKeys.userKey()
KeyType.MASTER -> myKeys.masterKey()
}?.unpaddedBase64PublicKey ?: throw NoSuchElementException("Cross Signing not configured")
val signaturesMadeByMyKey = signatures[myUserID] // Signatures made by me
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/UpdateTrustWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/UpdateTrustWorker.kt
index 6e317f049b..f1dc060e10 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/UpdateTrustWorker.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/UpdateTrustWorker.kt
@@ -149,7 +149,7 @@ internal class UpdateTrustWorker(context: Context, params: WorkerParameters, ses
val trusts = otherInfos.mapValues { entry ->
when (entry.key) {
myUserId -> myTrustResult
- else -> {
+ else -> {
crossSigningService.checkOtherMSKTrusted(myCrossSigningInfo, entry.value).also {
Timber.v("## CrossSigning - user:${entry.key} result:$it")
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/DefaultKeysBackupService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/DefaultKeysBackupService.kt
index 8ecb1d72c6..8691c08779 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/DefaultKeysBackupService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/DefaultKeysBackupService.kt
@@ -24,8 +24,10 @@ import androidx.annotation.WorkerThread
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
+import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext
import org.matrix.android.sdk.api.MatrixCallback
+import org.matrix.android.sdk.api.MatrixConfiguration
import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
import org.matrix.android.sdk.api.auth.data.Credentials
import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM_BACKUP
@@ -50,6 +52,7 @@ 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.util.awaitCallback
import org.matrix.android.sdk.api.util.fromBase64
+import org.matrix.android.sdk.internal.crypto.InboundGroupSessionStore
import org.matrix.android.sdk.internal.crypto.MXOlmDevice
import org.matrix.android.sdk.internal.crypto.MegolmSessionData
import org.matrix.android.sdk.internal.crypto.ObjectSigner
@@ -71,7 +74,7 @@ import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.GetRoomSessionsDa
import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.GetSessionsDataTask
import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.StoreSessionsDataTask
import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.UpdateKeysBackupVersionTask
-import org.matrix.android.sdk.internal.crypto.model.OlmInboundGroupSessionWrapper2
+import org.matrix.android.sdk.internal.crypto.model.MXInboundMegolmSessionWrapper
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
import org.matrix.android.sdk.internal.crypto.store.db.model.KeysBackupDataEntity
import org.matrix.android.sdk.internal.di.MoshiProvider
@@ -118,6 +121,8 @@ internal class DefaultKeysBackupService @Inject constructor(
private val updateKeysBackupVersionTask: UpdateKeysBackupVersionTask,
// Task executor
private val taskExecutor: TaskExecutor,
+ private val matrixConfiguration: MatrixConfiguration,
+ private val inboundGroupSessionStore: InboundGroupSessionStore,
private val coroutineDispatchers: MatrixCoroutineDispatchers,
private val cryptoCoroutineScope: CoroutineScope
) : KeysBackupService {
@@ -322,7 +327,7 @@ internal class DefaultKeysBackupService @Inject constructor(
// val hashServer = keysBackupData?.backupLastServerHash
return when {
- totalNumberOfKeysLocally < totalNumberOfKeysServer -> {
+ totalNumberOfKeysLocally < totalNumberOfKeysServer -> {
// Server contains more keys than this device
true
}
@@ -331,7 +336,7 @@ internal class DefaultKeysBackupService @Inject constructor(
// TODO We have not found any algorithm to determine if a restore is recommended here. Return false for the moment
false
}
- else -> false
+ else -> false
}
}
@@ -929,7 +934,7 @@ internal class DefaultKeysBackupService @Inject constructor(
*/
fun maybeBackupKeys() {
when {
- isStuck() -> {
+ isStuck() -> {
// If not already done, or in error case, check for a valid backup version on the homeserver.
// If there is one, maybeBackupKeys will be called again.
checkAndStartKeysBackup()
@@ -947,7 +952,7 @@ internal class DefaultKeysBackupService @Inject constructor(
uiHandler.post { backupKeys() }
}
}
- else -> {
+ else -> {
Timber.v("maybeBackupKeys: Skip it because state: ${getState()}")
}
}
@@ -992,7 +997,7 @@ internal class DefaultKeysBackupService @Inject constructor(
override fun onSuccess(data: KeysBackupLastVersionResult) {
val localBackupVersion = keysBackupVersion?.version
when (data) {
- KeysBackupLastVersionResult.NoKeysBackup -> {
+ KeysBackupLastVersionResult.NoKeysBackup -> {
if (localBackupVersion == null) {
// No backup on the server, and backup is not active
callback.onSuccess(true)
@@ -1316,7 +1321,7 @@ internal class DefaultKeysBackupService @Inject constructor(
olmInboundGroupSessionWrappers.forEach { olmInboundGroupSessionWrapper ->
val roomId = olmInboundGroupSessionWrapper.roomId ?: return@forEach
- val olmInboundGroupSession = olmInboundGroupSessionWrapper.olmInboundGroupSession ?: return@forEach
+ val olmInboundGroupSession = olmInboundGroupSessionWrapper.session
try {
encryptGroupSession(olmInboundGroupSessionWrapper)
@@ -1344,6 +1349,8 @@ internal class DefaultKeysBackupService @Inject constructor(
// Mark keys as backed up
cryptoStore.markBackupDoneForInboundGroupSessions(olmInboundGroupSessionWrappers)
+ // we can release the sessions now
+ olmInboundGroupSessionWrappers.onEach { it.session.releaseSession() }
if (olmInboundGroupSessionWrappers.size < KEY_BACKUP_SEND_KEYS_MAX_COUNT) {
Timber.v("backupKeys: All keys have been backed up")
@@ -1378,7 +1385,7 @@ internal class DefaultKeysBackupService @Inject constructor(
// Do not stay in KeysBackupState.WrongBackUpVersion but check what is available on the homeserver
checkAndStartKeysBackup()
}
- else ->
+ else ->
// Come back to the ready state so that we will retry on the next received key
keysBackupStateManager.state = KeysBackupState.ReadyToBackUp
}
@@ -1405,19 +1412,29 @@ internal class DefaultKeysBackupService @Inject constructor(
@VisibleForTesting
@WorkerThread
- fun encryptGroupSession(olmInboundGroupSessionWrapper: OlmInboundGroupSessionWrapper2): KeyBackupData? {
+ suspend fun encryptGroupSession(olmInboundGroupSessionWrapper: MXInboundMegolmSessionWrapper): KeyBackupData? {
+ olmInboundGroupSessionWrapper.safeSessionId ?: return null
+ olmInboundGroupSessionWrapper.senderKey ?: return null
// Gather information for each key
- val device = olmInboundGroupSessionWrapper.senderKey?.let { cryptoStore.deviceWithIdentityKey(it) }
+ val device = cryptoStore.deviceWithIdentityKey(olmInboundGroupSessionWrapper.senderKey)
// Build the m.megolm_backup.v1.curve25519-aes-sha2 data as defined at
// https://github.com/uhoreg/matrix-doc/blob/e2e_backup/proposals/1219-storing-megolm-keys-serverside.md#mmegolm_backupv1curve25519-aes-sha2-key-format
- val sessionData = olmInboundGroupSessionWrapper.exportKeys() ?: return null
+ val sessionData = inboundGroupSessionStore
+ .getInboundGroupSession(olmInboundGroupSessionWrapper.safeSessionId, olmInboundGroupSessionWrapper.senderKey)
+ ?.let {
+ withContext(coroutineDispatchers.computation) {
+ it.mutex.withLock { it.wrapper.exportKeys() }
+ }
+ }
+ ?: return null
val sessionBackupData = mapOf(
"algorithm" to sessionData.algorithm,
"sender_key" to sessionData.senderKey,
"sender_claimed_keys" to sessionData.senderClaimedKeys,
"forwarding_curve25519_key_chain" to (sessionData.forwardingCurve25519KeyChain.orEmpty()),
- "session_key" to sessionData.sessionKey
+ "session_key" to sessionData.sessionKey,
+ "org.matrix.msc3061.shared_history" to sessionData.sharedHistory
)
val json = MoshiProvider.providesMoshi()
@@ -1425,7 +1442,9 @@ internal class DefaultKeysBackupService @Inject constructor(
.toJson(sessionBackupData)
val encryptedSessionBackupData = try {
- backupOlmPkEncryption?.encrypt(json)
+ withContext(coroutineDispatchers.computation) {
+ backupOlmPkEncryption?.encrypt(json)
+ }
} catch (e: OlmException) {
Timber.e(e, "OlmException")
null
@@ -1435,14 +1454,14 @@ internal class DefaultKeysBackupService @Inject constructor(
// Build backup data for that key
return KeyBackupData(
firstMessageIndex = try {
- olmInboundGroupSessionWrapper.olmInboundGroupSession?.firstKnownIndex ?: 0
+ olmInboundGroupSessionWrapper.session.firstKnownIndex
} catch (e: OlmException) {
Timber.e(e, "OlmException")
0L
},
- forwardedCount = olmInboundGroupSessionWrapper.forwardingCurve25519KeyChain.orEmpty().size,
+ forwardedCount = olmInboundGroupSessionWrapper.sessionData.forwardingCurve25519KeyChain.orEmpty().size,
isVerified = device?.isVerified == true,
-
+ sharedHistory = olmInboundGroupSessionWrapper.getSharedKey(),
sessionData = mapOf(
"ciphertext" to encryptedSessionBackupData.mCipherText,
"mac" to encryptedSessionBackupData.mMac,
@@ -1451,6 +1470,14 @@ internal class DefaultKeysBackupService @Inject constructor(
)
}
+ /**
+ * Returns boolean shared key flag, if enabled with respect to matrix configuration.
+ */
+ private fun MXInboundMegolmSessionWrapper.getSharedKey(): Boolean {
+ if (!cryptoStore.isShareKeysOnInviteEnabled()) return false
+ return sessionData.sharedHistory
+ }
+
@VisibleForTesting
@WorkerThread
fun decryptKeyBackupData(keyBackupData: KeyBackupData, sessionId: String, roomId: String, decryption: OlmPkDecryption): MegolmSessionData? {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/model/rest/KeyBackupData.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/model/rest/KeyBackupData.kt
index 5c3d0c12b0..1817b18e2a 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/model/rest/KeyBackupData.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/model/rest/KeyBackupData.kt
@@ -50,5 +50,12 @@ internal data class KeyBackupData(
* Algorithm-dependent data.
*/
@Json(name = "session_data")
- val sessionData: JsonDict
+ val sessionData: JsonDict,
+
+ /**
+ * Flag that indicates whether or not the current inboundSession will be shared to
+ * invited users to decrypt past messages.
+ */
+ @Json(name = "org.matrix.msc3061.shared_history")
+ val sharedHistory: Boolean = false
)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/InboundGroupSessionData.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/InboundGroupSessionData.kt
new file mode 100644
index 0000000000..2ce36aa209
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/InboundGroupSessionData.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2022 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.internal.crypto.model
+
+import com.squareup.moshi.Json
+import com.squareup.moshi.JsonClass
+
+@JsonClass(generateAdapter = true)
+data class InboundGroupSessionData(
+
+ /** The room in which this session is used. */
+ @Json(name = "room_id")
+ var roomId: String? = null,
+
+ /** The base64-encoded curve25519 key of the sender. */
+ @Json(name = "sender_key")
+ var senderKey: String? = null,
+
+ /** Other keys the sender claims. */
+ @Json(name = "keys_claimed")
+ var keysClaimed: Map? = null,
+
+ /** Devices which forwarded this session to us (normally emty). */
+ @Json(name = "forwarding_curve25519_key_chain")
+ var forwardingCurve25519KeyChain: List? = emptyList(),
+
+ /** Not yet used, will be in backup v2
+ val untrusted?: Boolean = false */
+
+ /**
+ * Flag that indicates whether or not the current inboundSession will be shared to
+ * invited users to decrypt past messages.
+ */
+ @Json(name = "shared_history")
+ val sharedHistory: Boolean = false,
+
+ )
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/MXInboundMegolmSessionWrapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/MXInboundMegolmSessionWrapper.kt
new file mode 100644
index 0000000000..2772b34835
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/MXInboundMegolmSessionWrapper.kt
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2022 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.internal.crypto.model
+
+import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM
+import org.matrix.android.sdk.api.extensions.tryOrNull
+import org.matrix.android.sdk.internal.crypto.MegolmSessionData
+import org.matrix.olm.OlmInboundGroupSession
+import timber.log.Timber
+
+data class MXInboundMegolmSessionWrapper(
+ // olm object
+ val session: OlmInboundGroupSession,
+ // data about the session
+ val sessionData: InboundGroupSessionData
+) {
+ // shortcut
+ val roomId = sessionData.roomId
+ val senderKey = sessionData.senderKey
+ val safeSessionId = tryOrNull("Fail to get megolm session Id") { session.sessionIdentifier() }
+
+ /**
+ * Export the inbound group session keys.
+ * @param index the index to export. If null, the first known index will be used
+ * @return the inbound group session as MegolmSessionData if the operation succeeds
+ */
+ internal fun exportKeys(index: Long? = null): MegolmSessionData? {
+ return try {
+ val keysClaimed = sessionData.keysClaimed ?: return null
+ val wantedIndex = index ?: session.firstKnownIndex
+
+ MegolmSessionData(
+ senderClaimedEd25519Key = sessionData.keysClaimed?.get("ed25519"),
+ forwardingCurve25519KeyChain = sessionData.forwardingCurve25519KeyChain?.toList().orEmpty(),
+ sessionKey = session.export(wantedIndex),
+ senderClaimedKeys = keysClaimed,
+ roomId = sessionData.roomId,
+ sessionId = session.sessionIdentifier(),
+ senderKey = senderKey,
+ algorithm = MXCRYPTO_ALGORITHM_MEGOLM,
+ sharedHistory = sessionData.sharedHistory
+ )
+ } catch (e: Exception) {
+ Timber.e(e, "## Failed to export megolm : sessionID ${tryOrNull { session.sessionIdentifier() }} failed")
+ null
+ }
+ }
+
+ companion object {
+
+ /**
+ * @exportFormat true if the megolm keys are in export format
+ * (ie, they lack an ed25519 signature)
+ */
+ @Throws
+ internal fun newFromMegolmData(megolmSessionData: MegolmSessionData, exportFormat: Boolean): MXInboundMegolmSessionWrapper {
+ val exportedKey = megolmSessionData.sessionKey ?: throw IllegalArgumentException("key data not found")
+ val inboundSession = if (exportFormat) {
+ OlmInboundGroupSession.importSession(exportedKey)
+ } else {
+ OlmInboundGroupSession(exportedKey)
+ }
+ .also {
+ if (it.sessionIdentifier() != megolmSessionData.sessionId) {
+ it.releaseSession()
+ throw IllegalStateException("Mismatched group session Id")
+ }
+ }
+ val data = InboundGroupSessionData(
+ roomId = megolmSessionData.roomId,
+ senderKey = megolmSessionData.senderKey,
+ keysClaimed = megolmSessionData.senderClaimedKeys,
+ forwardingCurve25519KeyChain = megolmSessionData.forwardingCurve25519KeyChain,
+ sharedHistory = megolmSessionData.sharedHistory,
+ )
+
+ return MXInboundMegolmSessionWrapper(
+ inboundSession,
+ data
+ )
+ }
+ }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/OlmInboundGroupSessionWrapper2.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/OlmInboundGroupSessionWrapper2.kt
index 289c169d6d..600fcb1003 100755
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/OlmInboundGroupSessionWrapper2.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/OlmInboundGroupSessionWrapper2.kt
@@ -26,6 +26,8 @@ import java.io.Serializable
* This class adds more context to a OlmInboundGroupSession object.
* This allows additional checks. The class implements Serializable so that the context can be stored.
*/
+// Note used anymore, just for database migration
+// Deprecated("Use MXInboundMegolmSessionWrapper")
internal class OlmInboundGroupSessionWrapper2 : Serializable {
// The associated olm inbound group session.
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/OutboundGroupSessionWrapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/OutboundGroupSessionWrapper.kt
index 4ac87f44ce..5a6d1f4bc1 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/OutboundGroupSessionWrapper.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/OutboundGroupSessionWrapper.kt
@@ -20,5 +20,9 @@ import org.matrix.olm.OlmOutboundGroupSession
internal data class OutboundGroupSessionWrapper(
val outboundGroupSession: OlmOutboundGroupSession,
- val creationTime: Long
+ val creationTime: Long,
+ /**
+ * As per MSC 3061, declares if this key could be shared when inviting a new user to the room.
+ */
+ val sharedHistory: Boolean = false
)
diff --git a/vector/src/release/java/im/vector/app/features/debug/DebugMenuActivity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/SessionInfo.kt
similarity index 73%
rename from vector/src/release/java/im/vector/app/features/debug/DebugMenuActivity.kt
rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/SessionInfo.kt
index c5db033a18..b3a2ba4dfe 100644
--- a/vector/src/release/java/im/vector/app/features/debug/DebugMenuActivity.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/SessionInfo.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2019 New Vector Ltd
+ * 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.
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package im.vector.app.features.debug
+package org.matrix.android.sdk.internal.crypto.model
-import androidx.appcompat.app.AppCompatActivity
-
-// This activity is not accessible
-class DebugMenuActivity : AppCompatActivity()
+data class SessionInfo(
+ val sessionId: String,
+ val senderKey: String
+)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/VerificationMethodValues.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/VerificationMethodValues.kt
index c07434f586..afe6191bf7 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/VerificationMethodValues.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/VerificationMethodValues.kt
@@ -28,7 +28,7 @@ internal const val VERIFICATION_METHOD_RECIPROCATE = "m.reciprocate.v1"
internal fun VerificationMethod.toValue(): String {
return when (this) {
- VerificationMethod.SAS -> VERIFICATION_METHOD_SAS
+ VerificationMethod.SAS -> VERIFICATION_METHOD_SAS
VerificationMethod.QR_CODE_SCAN -> VERIFICATION_METHOD_QR_CODE_SCAN
VerificationMethod.QR_CODE_SHOW -> VERIFICATION_METHOD_QR_CODE_SHOW
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/secrets/DefaultSharedSecretStorageService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/secrets/DefaultSharedSecretStorageService.kt
index 0e9590a2d5..ddb048a912 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
@@ -179,7 +179,7 @@ internal class DefaultSharedSecretStorageService @Inject constructor(
throw SharedSecretStorageError.UnknownAlgorithm(key.keyInfo.content.algorithm ?: "")
}
}
- is KeyInfoResult.Error -> throw key.error
+ is KeyInfoResult.Error -> throw key.error
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCryptoStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCryptoStore.kt
index b18de34329..0413fc730c 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCryptoStore.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCryptoStore.kt
@@ -35,7 +35,7 @@ import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.events.model.content.RoomKeyWithHeldContent
import org.matrix.android.sdk.api.session.events.model.content.WithHeldCode
import org.matrix.android.sdk.api.util.Optional
-import org.matrix.android.sdk.internal.crypto.model.OlmInboundGroupSessionWrapper2
+import org.matrix.android.sdk.internal.crypto.model.MXInboundMegolmSessionWrapper
import org.matrix.android.sdk.internal.crypto.model.OlmSessionWrapper
import org.matrix.android.sdk.internal.crypto.model.OutboundGroupSessionWrapper
import org.matrix.android.sdk.internal.crypto.store.db.model.KeysBackupDataEntity
@@ -64,7 +64,15 @@ internal interface IMXCryptoStore {
*
* @return the list of all known group sessions, to export them.
*/
- fun getInboundGroupSessions(): List
+ fun getInboundGroupSessions(): List
+
+ /**
+ * Retrieve the known inbound group sessions for the specified room.
+ *
+ * @param roomId The roomId that the sessions will be returned
+ * @return the list of all known group sessions, for the provided roomId
+ */
+ fun getInboundGroupSessions(roomId: String): List
/**
* @return true to unilaterally blacklist all unverified devices.
@@ -90,6 +98,20 @@ internal interface IMXCryptoStore {
fun isKeyGossipingEnabled(): Boolean
+ /**
+ * As per MSC3061.
+ * If true will make it possible to share part of e2ee room history
+ * on invite depending on the room visibility setting.
+ */
+ fun enableShareKeyOnInvite(enable: Boolean)
+
+ /**
+ * As per MSC3061.
+ * If true will make it possible to share part of e2ee room history
+ * on invite depending on the room visibility setting.
+ */
+ fun isShareKeysOnInviteEnabled(): Boolean
+
/**
* Provides the rooms ids list in which the messages are not encrypted for the unverified devices.
*
@@ -250,6 +272,17 @@ internal interface IMXCryptoStore {
fun setShouldEncryptForInvitedMembers(roomId: String, shouldEncryptForInvitedMembers: Boolean)
+ fun shouldShareHistory(roomId: String): Boolean
+
+ /**
+ * Sets a boolean flag that will determine whether or not room history (existing inbound sessions)
+ * will be shared to new user invites.
+ *
+ * @param roomId the room id
+ * @param shouldShareHistory The boolean flag
+ */
+ fun setShouldShareHistory(roomId: String, shouldShareHistory: Boolean)
+
/**
* Store a session between the logged-in user and another device.
*
@@ -290,7 +323,7 @@ internal interface IMXCryptoStore {
*
* @param sessions the inbound group sessions to store.
*/
- fun storeInboundGroupSessions(sessions: List)
+ fun storeInboundGroupSessions(sessions: List)
/**
* Retrieve an inbound group session.
@@ -299,7 +332,17 @@ internal interface IMXCryptoStore {
* @param senderKey the base64-encoded curve25519 key of the sender.
* @return an inbound group session.
*/
- fun getInboundGroupSession(sessionId: String, senderKey: String): OlmInboundGroupSessionWrapper2?
+ fun getInboundGroupSession(sessionId: String, senderKey: String): MXInboundMegolmSessionWrapper?
+
+ /**
+ * Retrieve an inbound group session, filtering shared history.
+ *
+ * @param sessionId the session identifier.
+ * @param senderKey the base64-encoded curve25519 key of the sender.
+ * @param sharedHistory filter inbound session with respect to shared history field
+ * @return an inbound group session.
+ */
+ fun getInboundGroupSession(sessionId: String, senderKey: String, sharedHistory: Boolean): MXInboundMegolmSessionWrapper?
/**
* Get the current outbound group session for this encrypted room.
@@ -333,7 +376,7 @@ internal interface IMXCryptoStore {
*
* @param olmInboundGroupSessionWrappers the sessions
*/
- fun markBackupDoneForInboundGroupSessions(olmInboundGroupSessionWrappers: List)
+ fun markBackupDoneForInboundGroupSessions(olmInboundGroupSessionWrappers: List)
/**
* Retrieve inbound group sessions that are not yet backed up.
@@ -341,7 +384,7 @@ internal interface IMXCryptoStore {
* @param limit the maximum number of sessions to return.
* @return an array of non backed up inbound group sessions.
*/
- fun inboundGroupSessionsToBackup(limit: Int): List
+ fun inboundGroupSessionsToBackup(limit: Int): List
/**
* Number of stored inbound group sessions.
@@ -513,6 +556,5 @@ internal interface IMXCryptoStore {
fun setDeviceKeysUploaded(uploaded: Boolean)
fun areDeviceKeysUploaded(): Boolean
fun tidyUpDataBase()
- fun logDbUsageInfo()
fun getOutgoingRoomKeyRequests(inStates: Set): List
}
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 c56e4d320b..f5468634cb 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
@@ -50,7 +50,7 @@ import org.matrix.android.sdk.api.session.events.model.content.RoomKeyWithHeldCo
import org.matrix.android.sdk.api.session.events.model.content.WithHeldCode
import org.matrix.android.sdk.api.util.Optional
import org.matrix.android.sdk.api.util.toOptional
-import org.matrix.android.sdk.internal.crypto.model.OlmInboundGroupSessionWrapper2
+import org.matrix.android.sdk.internal.crypto.model.MXInboundMegolmSessionWrapper
import org.matrix.android.sdk.internal.crypto.model.OlmSessionWrapper
import org.matrix.android.sdk.internal.crypto.model.OutboundGroupSessionWrapper
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
@@ -88,7 +88,6 @@ import org.matrix.android.sdk.internal.crypto.store.db.query.get
import org.matrix.android.sdk.internal.crypto.store.db.query.getById
import org.matrix.android.sdk.internal.crypto.store.db.query.getOrCreate
import org.matrix.android.sdk.internal.crypto.util.RequestIdHelper
-import org.matrix.android.sdk.internal.database.tools.RealmDebugTools
import org.matrix.android.sdk.internal.di.CryptoDatabase
import org.matrix.android.sdk.internal.di.DeviceId
import org.matrix.android.sdk.internal.di.MoshiProvider
@@ -658,12 +657,28 @@ internal class RealmCryptoStore @Inject constructor(
?: false
}
+ override fun shouldShareHistory(roomId: String): Boolean {
+ if (!isShareKeysOnInviteEnabled()) return false
+ return doWithRealm(realmConfiguration) {
+ CryptoRoomEntity.getById(it, roomId)?.shouldShareHistory
+ }
+ ?: false
+ }
+
override fun setShouldEncryptForInvitedMembers(roomId: String, shouldEncryptForInvitedMembers: Boolean) {
doRealmTransaction(realmConfiguration) {
CryptoRoomEntity.getOrCreate(it, roomId).shouldEncryptForInvitedMembers = shouldEncryptForInvitedMembers
}
}
+ override fun setShouldShareHistory(roomId: String, shouldShareHistory: Boolean) {
+ Timber.tag(loggerTag.value)
+ .v("setShouldShareHistory for room $roomId is $shouldShareHistory")
+ doRealmTransaction(realmConfiguration) {
+ CryptoRoomEntity.getOrCreate(it, roomId).shouldShareHistory = shouldShareHistory
+ }
+ }
+
override fun storeSession(olmSessionWrapper: OlmSessionWrapper, deviceKey: String) {
var sessionIdentifier: String? = null
@@ -728,54 +743,61 @@ internal class RealmCryptoStore @Inject constructor(
}
}
- override fun storeInboundGroupSessions(sessions: List) {
+ override fun storeInboundGroupSessions(sessions: List) {
if (sessions.isEmpty()) {
return
}
doRealmTransaction(realmConfiguration) { realm ->
- sessions.forEach { session ->
- var sessionIdentifier: String? = null
+ sessions.forEach { wrapper ->
- try {
- sessionIdentifier = session.olmInboundGroupSession?.sessionIdentifier()
+ val sessionIdentifier = try {
+ wrapper.session.sessionIdentifier()
} catch (e: OlmException) {
Timber.e(e, "## storeInboundGroupSession() : sessionIdentifier failed")
+ return@forEach
}
- if (sessionIdentifier != null) {
- val key = OlmInboundGroupSessionEntity.createPrimaryKey(sessionIdentifier, session.senderKey)
+// val shouldShareHistory = session.roomId?.let { roomId ->
+// CryptoRoomEntity.getById(realm, roomId)?.shouldShareHistory
+// } ?: false
+ val key = OlmInboundGroupSessionEntity.createPrimaryKey(sessionIdentifier, wrapper.sessionData.senderKey)
- val existing = realm.where()
- .equalTo(OlmInboundGroupSessionEntityFields.PRIMARY_KEY, key)
- .findFirst()
+ val existing = realm.where()
+ .equalTo(OlmInboundGroupSessionEntityFields.PRIMARY_KEY, key)
+ .findFirst()
- if (existing != null) {
- // we want to keep the existing backup status
- existing.putInboundGroupSession(session)
- } else {
- val realmOlmInboundGroupSession = OlmInboundGroupSessionEntity().apply {
- primaryKey = key
- sessionId = sessionIdentifier
- senderKey = session.senderKey
- putInboundGroupSession(session)
- }
-
- realm.insertOrUpdate(realmOlmInboundGroupSession)
- }
+ val realmOlmInboundGroupSession = OlmInboundGroupSessionEntity().apply {
+ primaryKey = key
+ store(wrapper)
+ backedUp = existing?.backedUp ?: false
}
+
+ Timber.v("## CRYPTO | shouldShareHistory: ${wrapper.sessionData.sharedHistory} for $key")
+ realm.insertOrUpdate(realmOlmInboundGroupSession)
}
}
}
- override fun getInboundGroupSession(sessionId: String, senderKey: String): OlmInboundGroupSessionWrapper2? {
+ override fun getInboundGroupSession(sessionId: String, senderKey: String): MXInboundMegolmSessionWrapper? {
val key = OlmInboundGroupSessionEntity.createPrimaryKey(sessionId, senderKey)
- return doWithRealm(realmConfiguration) {
- it.where()
+ return doWithRealm(realmConfiguration) { realm ->
+ realm.where()
.equalTo(OlmInboundGroupSessionEntityFields.PRIMARY_KEY, key)
.findFirst()
- ?.getInboundGroupSession()
+ ?.toModel()
+ }
+ }
+
+ override fun getInboundGroupSession(sessionId: String, senderKey: String, sharedHistory: Boolean): MXInboundMegolmSessionWrapper? {
+ val key = OlmInboundGroupSessionEntity.createPrimaryKey(sessionId, senderKey)
+ return doWithRealm(realmConfiguration) {
+ it.where()
+ .equalTo(OlmInboundGroupSessionEntityFields.SHARED_HISTORY, sharedHistory)
+ .equalTo(OlmInboundGroupSessionEntityFields.PRIMARY_KEY, key)
+ .findFirst()
+ ?.toModel()
}
}
@@ -787,7 +809,8 @@ internal class RealmCryptoStore @Inject constructor(
entity.getOutboundGroupSession()?.let {
OutboundGroupSessionWrapper(
it,
- entity.creationTime ?: 0
+ entity.creationTime ?: 0,
+ entity.shouldShareHistory
)
}
}
@@ -807,6 +830,8 @@ internal class RealmCryptoStore @Inject constructor(
if (outboundGroupSession != null) {
val info = realm.createObject(OutboundGroupSessionInfoEntity::class.java).apply {
creationTime = clock.epochMillis()
+ // Store the room history visibility on the outbound session creation
+ shouldShareHistory = entity.shouldShareHistory
putOutboundGroupSession(outboundGroupSession)
}
entity.outboundSessionInfo = info
@@ -815,17 +840,32 @@ internal class RealmCryptoStore @Inject constructor(
}
}
+// override fun needsRotationDueToVisibilityChange(roomId: String): Boolean {
+// return doWithRealm(realmConfiguration) { realm ->
+// CryptoRoomEntity.getById(realm, roomId)?.let { entity ->
+// entity.shouldShareHistory != entity.outboundSessionInfo?.shouldShareHistory
+// }
+// } ?: false
+// }
+
/**
* Note: the result will be only use to export all the keys and not to use the OlmInboundGroupSessionWrapper2,
* so there is no need to use or update `inboundGroupSessionToRelease` for native memory management.
*/
- override fun getInboundGroupSessions(): List {
- return doWithRealm(realmConfiguration) {
- it.where()
+ override fun getInboundGroupSessions(): List {
+ return doWithRealm(realmConfiguration) { realm ->
+ realm.where()
.findAll()
- .mapNotNull { inboundGroupSessionEntity ->
- inboundGroupSessionEntity.getInboundGroupSession()
- }
+ .mapNotNull { it.toModel() }
+ }
+ }
+
+ override fun getInboundGroupSessions(roomId: String): List {
+ return doWithRealm(realmConfiguration) { realm ->
+ realm.where()
+ .equalTo(OlmInboundGroupSessionEntityFields.ROOM_ID, roomId)
+ .findAll()
+ .mapNotNull { it.toModel() }
}
}
@@ -886,7 +926,7 @@ internal class RealmCryptoStore @Inject constructor(
}
}
- override fun markBackupDoneForInboundGroupSessions(olmInboundGroupSessionWrappers: List) {
+ override fun markBackupDoneForInboundGroupSessions(olmInboundGroupSessionWrappers: List) {
if (olmInboundGroupSessionWrappers.isEmpty()) {
return
}
@@ -894,10 +934,13 @@ internal class RealmCryptoStore @Inject constructor(
doRealmTransaction(realmConfiguration) { realm ->
olmInboundGroupSessionWrappers.forEach { olmInboundGroupSessionWrapper ->
try {
- val sessionIdentifier = olmInboundGroupSessionWrapper.olmInboundGroupSession?.sessionIdentifier()
+ val sessionIdentifier =
+ tryOrNull("Failed to get session identifier") {
+ olmInboundGroupSessionWrapper.session.sessionIdentifier()
+ } ?: return@forEach
val key = OlmInboundGroupSessionEntity.createPrimaryKey(
sessionIdentifier,
- olmInboundGroupSessionWrapper.senderKey
+ olmInboundGroupSessionWrapper.sessionData.senderKey
)
val existing = realm.where()
@@ -910,9 +953,7 @@ internal class RealmCryptoStore @Inject constructor(
// ... might be in cache but not yet persisted, create a record to persist backedup state
val realmOlmInboundGroupSession = OlmInboundGroupSessionEntity().apply {
primaryKey = key
- sessionId = sessionIdentifier
- senderKey = olmInboundGroupSessionWrapper.senderKey
- putInboundGroupSession(olmInboundGroupSessionWrapper)
+ store(olmInboundGroupSessionWrapper)
backedUp = true
}
@@ -925,15 +966,13 @@ internal class RealmCryptoStore @Inject constructor(
}
}
- override fun inboundGroupSessionsToBackup(limit: Int): List {
+ override fun inboundGroupSessionsToBackup(limit: Int): List {
return doWithRealm(realmConfiguration) {
it.where()
.equalTo(OlmInboundGroupSessionEntityFields.BACKED_UP, false)
.limit(limit.toLong())
.findAll()
- .mapNotNull { inboundGroupSession ->
- inboundGroupSession.getInboundGroupSession()
- }
+ .mapNotNull { it.toModel() }
}
}
@@ -974,6 +1013,18 @@ internal class RealmCryptoStore @Inject constructor(
} ?: false
}
+ override fun isShareKeysOnInviteEnabled(): Boolean {
+ return doWithRealm(realmConfiguration) {
+ it.where().findFirst()?.enableKeyForwardingOnInvite
+ } ?: false
+ }
+
+ override fun enableShareKeyOnInvite(enable: Boolean) {
+ doRealmTransaction(realmConfiguration) {
+ it.where().findFirst()?.enableKeyForwardingOnInvite = enable
+ }
+ }
+
override fun setDeviceKeysUploaded(uploaded: Boolean) {
doRealmTransaction(realmConfiguration) {
it.where().findFirst()?.deviceKeysSentToServer = uploaded
@@ -1709,11 +1760,4 @@ internal class RealmCryptoStore @Inject constructor(
// Can we do something for WithHeldSessionEntity?
}
}
-
- /**
- * Prints out database info.
- */
- override fun logDbUsageInfo() {
- RealmDebugTools(realmConfiguration).logInfo("Crypto")
- }
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStoreMigration.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStoreMigration.kt
index 02c2a27dec..c36d572da6 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStoreMigration.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStoreMigration.kt
@@ -17,7 +17,6 @@
package org.matrix.android.sdk.internal.crypto.store.db
import io.realm.DynamicRealm
-import io.realm.RealmMigration
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo001Legacy
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo002Legacy
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo003RiotX
@@ -34,13 +33,23 @@ import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo014
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo015
import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo016
+import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo017
+import org.matrix.android.sdk.internal.util.database.MatrixRealmMigration
import org.matrix.android.sdk.internal.util.time.Clock
-import timber.log.Timber
import javax.inject.Inject
+/**
+ * Schema version history:
+ * 0, 1, 2: legacy Riot-Android;
+ * 3: migrate to RiotX schema;
+ * 4, 5, 6, 7, 8, 9: migrations from RiotX (which was previously 1, 2, 3, 4, 5, 6).
+ */
internal class RealmCryptoStoreMigration @Inject constructor(
private val clock: Clock,
-) : RealmMigration {
+) : MatrixRealmMigration(
+ dbName = "Crypto",
+ schemaVersion = 17L,
+) {
/**
* Forces all RealmCryptoStoreMigration instances to be equal.
* Avoids Realm throwing when multiple instances of the migration are set.
@@ -48,14 +57,7 @@ internal class RealmCryptoStoreMigration @Inject constructor(
override fun equals(other: Any?) = other is RealmCryptoStoreMigration
override fun hashCode() = 5000
- // 0, 1, 2: legacy Riot-Android
- // 3: migrate to RiotX schema
- // 4, 5, 6, 7, 8, 9: migrations from RiotX (which was previously 1, 2, 3, 4, 5, 6)
- val schemaVersion = 16L
-
- override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) {
- Timber.d("Migrating Realm Crypto from $oldVersion to $newVersion")
-
+ override fun doMigrate(realm: DynamicRealm, oldVersion: Long) {
if (oldVersion < 1) MigrateCryptoTo001Legacy(realm).perform()
if (oldVersion < 2) MigrateCryptoTo002Legacy(realm).perform()
if (oldVersion < 3) MigrateCryptoTo003RiotX(realm).perform()
@@ -72,5 +74,6 @@ internal class RealmCryptoStoreMigration @Inject constructor(
if (oldVersion < 14) MigrateCryptoTo014(realm).perform()
if (oldVersion < 15) MigrateCryptoTo015(realm).perform()
if (oldVersion < 16) MigrateCryptoTo016(realm).perform()
+ if (oldVersion < 17) MigrateCryptoTo017(realm).perform()
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo004.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo004.kt
index e5bdd2aa9b..0a986892d9 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo004.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo004.kt
@@ -104,10 +104,10 @@ internal class MigrateCryptoTo004(realm: DynamicRealm) : RealmMigrator(realm, 4)
val trustLevel = realm.createObject("TrustLevelEntity")
when (oldDevice.verified) {
- MXDeviceInfo.DEVICE_VERIFICATION_UNKNOWN -> {
+ MXDeviceInfo.DEVICE_VERIFICATION_UNKNOWN -> {
obj.setNull(DeviceInfoEntityFields.TRUST_LEVEL_ENTITY.`$`)
}
- MXDeviceInfo.DEVICE_VERIFICATION_BLOCKED -> {
+ MXDeviceInfo.DEVICE_VERIFICATION_BLOCKED -> {
trustLevel.setNull(TrustLevelEntityFields.LOCALLY_VERIFIED)
trustLevel.setNull(TrustLevelEntityFields.CROSS_SIGNED_VERIFIED)
obj.setBoolean(DeviceInfoEntityFields.IS_BLOCKED, oldDevice.isBlocked)
@@ -118,7 +118,7 @@ internal class MigrateCryptoTo004(realm: DynamicRealm) : RealmMigrator(realm, 4)
trustLevel.setBoolean(TrustLevelEntityFields.CROSS_SIGNED_VERIFIED, false)
obj.setObject(DeviceInfoEntityFields.TRUST_LEVEL_ENTITY.`$`, trustLevel)
}
- MXDeviceInfo.DEVICE_VERIFICATION_VERIFIED -> {
+ MXDeviceInfo.DEVICE_VERIFICATION_VERIFIED -> {
trustLevel.setBoolean(TrustLevelEntityFields.LOCALLY_VERIFIED, true)
trustLevel.setBoolean(TrustLevelEntityFields.CROSS_SIGNED_VERIFIED, false)
obj.setObject(DeviceInfoEntityFields.TRUST_LEVEL_ENTITY.`$`, trustLevel)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo017.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo017.kt
new file mode 100644
index 0000000000..8904c412cd
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo017.kt
@@ -0,0 +1,101 @@
+/*
+ * 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.crypto.store.db.migration
+
+import io.realm.DynamicRealm
+import org.matrix.android.sdk.api.extensions.tryOrNull
+import org.matrix.android.sdk.internal.crypto.model.InboundGroupSessionData
+import org.matrix.android.sdk.internal.crypto.store.db.deserializeFromRealm
+import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMetadataEntityFields
+import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoRoomEntityFields
+import org.matrix.android.sdk.internal.crypto.store.db.model.OlmInboundGroupSessionEntityFields
+import org.matrix.android.sdk.internal.crypto.store.db.model.OutboundGroupSessionInfoEntityFields
+import org.matrix.android.sdk.internal.crypto.store.db.serializeForRealm
+import org.matrix.android.sdk.internal.di.MoshiProvider
+import org.matrix.android.sdk.internal.util.database.RealmMigrator
+import timber.log.Timber
+
+/**
+ * Version 17L enhance OlmInboundGroupSessionEntity to support shared history for MSC3061.
+ * Also migrates how megolm session are stored to avoid additional serialized frozen class.
+ */
+internal class MigrateCryptoTo017(realm: DynamicRealm) : RealmMigrator(realm, 17) {
+
+ override fun doMigrate(realm: DynamicRealm) {
+ realm.schema.get("CryptoRoomEntity")
+ ?.addField(CryptoRoomEntityFields.SHOULD_SHARE_HISTORY, Boolean::class.java)?.transform {
+ // We don't have access to the session database to check for the state here and set the good value.
+ // But for now as it's behind a lab flag, will set to false and force initial sync when enabled
+ it.setBoolean(CryptoRoomEntityFields.SHOULD_SHARE_HISTORY, false)
+ }
+
+ realm.schema.get("OutboundGroupSessionInfoEntity")
+ ?.addField(OutboundGroupSessionInfoEntityFields.SHOULD_SHARE_HISTORY, Boolean::class.java)?.transform {
+ // We don't have access to the session database to check for the state here and set the good value.
+ // But for now as it's behind a lab flag, will set to false and force initial sync when enabled
+ it.setBoolean(OutboundGroupSessionInfoEntityFields.SHOULD_SHARE_HISTORY, false)
+ }
+
+ realm.schema.get("CryptoMetadataEntity")
+ ?.addField(CryptoMetadataEntityFields.ENABLE_KEY_FORWARDING_ON_INVITE, Boolean::class.java)
+ ?.transform { obj ->
+ // default to false
+ obj.setBoolean(CryptoMetadataEntityFields.ENABLE_KEY_FORWARDING_ON_INVITE, false)
+ }
+
+ val moshiAdapter = MoshiProvider.providesMoshi().adapter(InboundGroupSessionData::class.java)
+
+ realm.schema.get("OlmInboundGroupSessionEntity")
+ ?.addField(OlmInboundGroupSessionEntityFields.SHARED_HISTORY, Boolean::class.java)
+ ?.addField(OlmInboundGroupSessionEntityFields.ROOM_ID, String::class.java)
+ ?.addField(OlmInboundGroupSessionEntityFields.INBOUND_GROUP_SESSION_DATA_JSON, String::class.java)
+ ?.addField(OlmInboundGroupSessionEntityFields.SERIALIZED_OLM_INBOUND_GROUP_SESSION, String::class.java)
+ ?.transform { dynamicObject ->
+ try {
+ // we want to convert the old wrapper frozen class into a
+ // map of sessionData & the pickled session herself
+ dynamicObject.getString(OlmInboundGroupSessionEntityFields.OLM_INBOUND_GROUP_SESSION_DATA)?.let { oldData ->
+ val oldWrapper = tryOrNull("Failed to convert megolm inbound group data") {
+ @Suppress("DEPRECATION")
+ deserializeFromRealm(oldData)
+ }
+ val groupSession = oldWrapper?.olmInboundGroupSession
+ ?: return@transform Unit.also {
+ Timber.w("Failed to migrate megolm session, no olmInboundGroupSession")
+ }
+ // now convert to new data
+ val data = InboundGroupSessionData(
+ senderKey = oldWrapper.senderKey,
+ roomId = oldWrapper.roomId,
+ keysClaimed = oldWrapper.keysClaimed,
+ forwardingCurve25519KeyChain = oldWrapper.forwardingCurve25519KeyChain,
+ sharedHistory = false,
+ )
+
+ dynamicObject.setString(OlmInboundGroupSessionEntityFields.INBOUND_GROUP_SESSION_DATA_JSON, moshiAdapter.toJson(data))
+ dynamicObject.setString(OlmInboundGroupSessionEntityFields.SERIALIZED_OLM_INBOUND_GROUP_SESSION, serializeForRealm(groupSession))
+
+ // denormalized fields
+ dynamicObject.setString(OlmInboundGroupSessionEntityFields.ROOM_ID, oldWrapper.roomId)
+ dynamicObject.setBoolean(OlmInboundGroupSessionEntityFields.SHARED_HISTORY, false)
+ }
+ } catch (failure: Throwable) {
+ Timber.e(failure, "Failed to migrate megolm session")
+ }
+ }
+ }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/AuditTrailMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/AuditTrailMapper.kt
index 80ae4a8d0d..fe8e9f1db7 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/AuditTrailMapper.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/AuditTrailMapper.kt
@@ -30,7 +30,7 @@ internal object AuditTrailMapper {
fun map(entity: AuditTrailEntity): AuditTrail? {
val contentJson = entity.contentJson ?: return null
return when (entity.type) {
- TrailType.OutgoingKeyForward.name -> {
+ TrailType.OutgoingKeyForward.name -> {
val info = tryOrNull {
MoshiProvider.providesMoshi().adapter(ForwardInfo::class.java).fromJson(contentJson)
} ?: return null
@@ -50,7 +50,7 @@ internal object AuditTrailMapper {
info = info
)
}
- TrailType.IncomingKeyRequest.name -> {
+ TrailType.IncomingKeyRequest.name -> {
val info = tryOrNull {
MoshiProvider.providesMoshi().adapter(IncomingKeyRequestInfo::class.java).fromJson(contentJson)
} ?: return null
@@ -60,7 +60,7 @@ internal object AuditTrailMapper {
info = info
)
}
- TrailType.IncomingKeyForward.name -> {
+ TrailType.IncomingKeyForward.name -> {
val info = tryOrNull {
MoshiProvider.providesMoshi().adapter(ForwardInfo::class.java).fromJson(contentJson)
} ?: return null
@@ -70,7 +70,7 @@ internal object AuditTrailMapper {
info = info
)
}
- else -> {
+ else -> {
AuditTrail(
ageLocalTs = entity.ageLocalTs ?: 0,
type = TrailType.Unknown,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/CryptoMetadataEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/CryptoMetadataEntity.kt
index 63ed0e537e..88708f824e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/CryptoMetadataEntity.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/CryptoMetadataEntity.kt
@@ -35,6 +35,11 @@ internal open class CryptoMetadataEntity(
var globalBlacklistUnverifiedDevices: Boolean = false,
// setting to enable or disable key gossiping
var globalEnableKeyGossiping: Boolean = true,
+
+ // MSC3061: Sharing room keys for past messages
+ // If set to true key history will be shared to invited users with respect to room setting
+ var enableKeyForwardingOnInvite: Boolean = false,
+
// The keys backup version currently used. Null means no backup.
var backupVersion: String? = null,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/CryptoRoomEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/CryptoRoomEntity.kt
index 114a596964..be57586163 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/CryptoRoomEntity.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/CryptoRoomEntity.kt
@@ -24,6 +24,8 @@ internal open class CryptoRoomEntity(
var algorithm: String? = null,
var shouldEncryptForInvitedMembers: Boolean? = null,
var blacklistUnverifiedDevices: Boolean = false,
+ // Determines whether or not room history should be shared on new member invites
+ var shouldShareHistory: Boolean = false,
// Store the current outbound session for this room,
// to avoid re-create and re-share at each startup (if rotation not needed..)
// This is specific to megolm but not sure how to model it better
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/OlmInboundGroupSessionEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/OlmInboundGroupSessionEntity.kt
index a4f6c279ac..62ab73e379 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/OlmInboundGroupSessionEntity.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/OlmInboundGroupSessionEntity.kt
@@ -18,9 +18,12 @@ package org.matrix.android.sdk.internal.crypto.store.db.model
import io.realm.RealmObject
import io.realm.annotations.PrimaryKey
-import org.matrix.android.sdk.internal.crypto.model.OlmInboundGroupSessionWrapper2
+import org.matrix.android.sdk.internal.crypto.model.InboundGroupSessionData
+import org.matrix.android.sdk.internal.crypto.model.MXInboundMegolmSessionWrapper
import org.matrix.android.sdk.internal.crypto.store.db.deserializeFromRealm
import org.matrix.android.sdk.internal.crypto.store.db.serializeForRealm
+import org.matrix.android.sdk.internal.di.MoshiProvider
+import org.matrix.olm.OlmInboundGroupSession
import timber.log.Timber
internal fun OlmInboundGroupSessionEntity.Companion.createPrimaryKey(sessionId: String?, senderKey: String?) = "$sessionId|$senderKey"
@@ -28,27 +31,83 @@ internal fun OlmInboundGroupSessionEntity.Companion.createPrimaryKey(sessionId:
internal open class OlmInboundGroupSessionEntity(
// Combined value to build a primary key
@PrimaryKey var primaryKey: String? = null,
+
+ // denormalization for faster querying (these fields are in the inboundGroupSessionDataJson)
var sessionId: String? = null,
var senderKey: String? = null,
- // olmInboundGroupSessionData contains Json
+ var roomId: String? = null,
+
+ // Deprecated, used for migration / olmInboundGroupSessionData contains Json
+ // keep it in case of problem to have a chance to recover
var olmInboundGroupSessionData: String? = null,
+
+ // Stores the session data in an extensible format
+ // to allow to store data not yet supported for later use
+ var inboundGroupSessionDataJson: String? = null,
+
+ // The pickled session
+ var serializedOlmInboundGroupSession: String? = null,
+
+ // Flag that indicates whether or not the current inboundSession will be shared to
+ // invited users to decrypt past messages
+ var sharedHistory: Boolean = false,
// Indicate if the key has been backed up to the homeserver
var backedUp: Boolean = false
) :
RealmObject() {
- fun getInboundGroupSession(): OlmInboundGroupSessionWrapper2? {
+ fun store(wrapper: MXInboundMegolmSessionWrapper) {
+ this.serializedOlmInboundGroupSession = serializeForRealm(wrapper.session)
+ this.inboundGroupSessionDataJson = adapter.toJson(wrapper.sessionData)
+ this.roomId = wrapper.sessionData.roomId
+ this.senderKey = wrapper.sessionData.senderKey
+ this.sessionId = wrapper.session.sessionIdentifier()
+ this.sharedHistory = wrapper.sessionData.sharedHistory
+ }
+// fun getInboundGroupSession(): OlmInboundGroupSessionWrapper2? {
+// return try {
+// deserializeFromRealm(olmInboundGroupSessionData)
+// } catch (failure: Throwable) {
+// Timber.e(failure, "## Deserialization failure")
+// return null
+// }
+// }
+//
+// fun putInboundGroupSession(olmInboundGroupSessionWrapper: OlmInboundGroupSessionWrapper2?) {
+// olmInboundGroupSessionData = serializeForRealm(olmInboundGroupSessionWrapper)
+// }
+
+ fun getOlmGroupSession(): OlmInboundGroupSession? {
return try {
- deserializeFromRealm(olmInboundGroupSessionData)
+ deserializeFromRealm(serializedOlmInboundGroupSession)
} catch (failure: Throwable) {
Timber.e(failure, "## Deserialization failure")
return null
}
}
- fun putInboundGroupSession(olmInboundGroupSessionWrapper: OlmInboundGroupSessionWrapper2?) {
- olmInboundGroupSessionData = serializeForRealm(olmInboundGroupSessionWrapper)
+ fun getData(): InboundGroupSessionData? {
+ return try {
+ inboundGroupSessionDataJson?.let {
+ adapter.fromJson(it)
+ }
+ } catch (failure: Throwable) {
+ Timber.e(failure, "## Deserialization failure")
+ return null
+ }
}
- companion object
+ fun toModel(): MXInboundMegolmSessionWrapper? {
+ val data = getData() ?: return null
+ val session = getOlmGroupSession() ?: return null
+ return MXInboundMegolmSessionWrapper(
+ session = session,
+ sessionData = data
+ )
+ }
+
+ companion object {
+ private val adapter = MoshiProvider.providesMoshi()
+ .adapter(InboundGroupSessionData::class.java)
+ }
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/OutboundGroupSessionInfoEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/OutboundGroupSessionInfoEntity.kt
index d50db78415..2ebd550201 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/OutboundGroupSessionInfoEntity.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/OutboundGroupSessionInfoEntity.kt
@@ -24,7 +24,8 @@ import timber.log.Timber
internal open class OutboundGroupSessionInfoEntity(
var serializedOutboundSessionData: String? = null,
- var creationTime: Long? = null
+ var creationTime: Long? = null,
+ var shouldShareHistory: Boolean = false
) : RealmObject() {
fun getOutboundGroupSession(): OlmOutboundGroupSession? {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/OutgoingKeyRequestEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/OutgoingKeyRequestEntity.kt
index 854d148b76..b10e7501d6 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/OutgoingKeyRequestEntity.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/OutgoingKeyRequestEntity.kt
@@ -117,7 +117,7 @@ internal open class OutgoingKeyRequestEntity(
private fun eventToResult(event: Event): RequestResult? {
return when (event.getClearType()) {
- EventType.ROOM_KEY_WITHHELD -> {
+ in EventType.ROOM_KEY_WITHHELD.values -> {
event.content.toModel()?.code?.let {
RequestResult.Failure(it)
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SendEventTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SendEventTask.kt
index fbd9d245d9..bb14b417dd 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SendEventTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SendEventTask.kt
@@ -15,7 +15,6 @@
*/
package org.matrix.android.sdk.internal.crypto.tasks
-import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.room.send.SendState
import org.matrix.android.sdk.internal.network.GlobalErrorReceiver
@@ -48,8 +47,12 @@ internal class DefaultSendEventTask @Inject constructor(
params.event.roomId
?.takeIf { params.encrypt }
?.let { roomId ->
- tryOrNull {
+ try {
loadRoomMembersTask.execute(LoadRoomMembersTask.Params(roomId))
+ } catch (failure: Throwable) {
+ // send any way?
+ // the result is that some users won't probably be able to decrypt :/
+ Timber.w(failure, "SendEvent: failed to load members in room ${params.event.roomId}")
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultIncomingSASDefaultVerificationTransaction.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultIncomingSASDefaultVerificationTransaction.kt
index a9d5cf1191..6b3bb1e641 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultIncomingSASDefaultVerificationTransaction.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultIncomingSASDefaultVerificationTransaction.kt
@@ -60,26 +60,26 @@ internal class DefaultIncomingSASDefaultVerificationTransaction(
override val uxState: IncomingSasVerificationTransaction.UxState
get() {
return when (val immutableState = state) {
- is VerificationTxState.OnStarted -> IncomingSasVerificationTransaction.UxState.SHOW_ACCEPT
+ is VerificationTxState.OnStarted -> IncomingSasVerificationTransaction.UxState.SHOW_ACCEPT
is VerificationTxState.SendingAccept,
is VerificationTxState.Accepted,
is VerificationTxState.OnKeyReceived,
is VerificationTxState.SendingKey,
- is VerificationTxState.KeySent -> IncomingSasVerificationTransaction.UxState.WAIT_FOR_KEY_AGREEMENT
+ is VerificationTxState.KeySent -> IncomingSasVerificationTransaction.UxState.WAIT_FOR_KEY_AGREEMENT
is VerificationTxState.ShortCodeReady -> IncomingSasVerificationTransaction.UxState.SHOW_SAS
is VerificationTxState.ShortCodeAccepted,
is VerificationTxState.SendingMac,
is VerificationTxState.MacSent,
- is VerificationTxState.Verifying -> IncomingSasVerificationTransaction.UxState.WAIT_FOR_VERIFICATION
- is VerificationTxState.Verified -> IncomingSasVerificationTransaction.UxState.VERIFIED
- is VerificationTxState.Cancelled -> {
+ is VerificationTxState.Verifying -> IncomingSasVerificationTransaction.UxState.WAIT_FOR_VERIFICATION
+ is VerificationTxState.Verified -> IncomingSasVerificationTransaction.UxState.VERIFIED
+ is VerificationTxState.Cancelled -> {
if (immutableState.byMe) {
IncomingSasVerificationTransaction.UxState.CANCELLED_BY_ME
} else {
IncomingSasVerificationTransaction.UxState.CANCELLED_BY_OTHER
}
}
- else -> IncomingSasVerificationTransaction.UxState.UNKNOWN
+ else -> IncomingSasVerificationTransaction.UxState.UNKNOWN
}
}
@@ -232,7 +232,7 @@ internal class DefaultIncomingSASDefaultVerificationTransaction(
val sasInfo = "MATRIX_KEY_VERIFICATION_SAS|$otherUserId|$otherDeviceId|$otherKey|$userId|$deviceId|${getSAS().publicKey}|$transactionId"
return getSAS().generateShortCode(sasInfo, 6)
}
- else -> {
+ else -> {
// Protocol has been checked earlier
throw IllegalArgumentException()
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultOutgoingSASDefaultVerificationTransaction.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultOutgoingSASDefaultVerificationTransaction.kt
index ddb8ed232b..f1cf1b7547 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultOutgoingSASDefaultVerificationTransaction.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultOutgoingSASDefaultVerificationTransaction.kt
@@ -57,27 +57,27 @@ internal class DefaultOutgoingSASDefaultVerificationTransaction(
override val uxState: OutgoingSasVerificationTransaction.UxState
get() {
return when (val immutableState = state) {
- is VerificationTxState.None -> OutgoingSasVerificationTransaction.UxState.WAIT_FOR_START
+ is VerificationTxState.None -> OutgoingSasVerificationTransaction.UxState.WAIT_FOR_START
is VerificationTxState.SendingStart,
is VerificationTxState.Started,
is VerificationTxState.OnAccepted,
is VerificationTxState.SendingKey,
is VerificationTxState.KeySent,
- is VerificationTxState.OnKeyReceived -> OutgoingSasVerificationTransaction.UxState.WAIT_FOR_KEY_AGREEMENT
+ is VerificationTxState.OnKeyReceived -> OutgoingSasVerificationTransaction.UxState.WAIT_FOR_KEY_AGREEMENT
is VerificationTxState.ShortCodeReady -> OutgoingSasVerificationTransaction.UxState.SHOW_SAS
is VerificationTxState.ShortCodeAccepted,
is VerificationTxState.SendingMac,
is VerificationTxState.MacSent,
- is VerificationTxState.Verifying -> OutgoingSasVerificationTransaction.UxState.WAIT_FOR_VERIFICATION
- is VerificationTxState.Verified -> OutgoingSasVerificationTransaction.UxState.VERIFIED
- is VerificationTxState.Cancelled -> {
+ is VerificationTxState.Verifying -> OutgoingSasVerificationTransaction.UxState.WAIT_FOR_VERIFICATION
+ is VerificationTxState.Verified -> OutgoingSasVerificationTransaction.UxState.VERIFIED
+ is VerificationTxState.Cancelled -> {
if (immutableState.byMe) {
OutgoingSasVerificationTransaction.UxState.CANCELLED_BY_OTHER
} else {
OutgoingSasVerificationTransaction.UxState.CANCELLED_BY_ME
}
}
- else -> OutgoingSasVerificationTransaction.UxState.UNKNOWN
+ else -> OutgoingSasVerificationTransaction.UxState.UNKNOWN
}
}
@@ -224,7 +224,7 @@ internal class DefaultOutgoingSASDefaultVerificationTransaction(
val sasInfo = "MATRIX_KEY_VERIFICATION_SAS|$userId|$deviceId|${getSAS().publicKey}|$otherUserId|$otherDeviceId|$otherKey|$transactionId"
return getSAS().generateShortCode(sasInfo, 6)
}
- else -> {
+ else -> {
// Protocol has been checked earlier
throw IllegalArgumentException()
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultVerificationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultVerificationService.kt
index 7d8245da30..1a04ee0302 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultVerificationService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultVerificationService.kt
@@ -129,31 +129,31 @@ internal class DefaultVerificationService @Inject constructor(
Timber.d("## SAS onToDeviceEvent ${event.getClearType()}")
cryptoCoroutineScope.launch(coroutineDispatchers.dmVerif) {
when (event.getClearType()) {
- EventType.KEY_VERIFICATION_START -> {
+ EventType.KEY_VERIFICATION_START -> {
onStartRequestReceived(event)
}
- EventType.KEY_VERIFICATION_CANCEL -> {
+ EventType.KEY_VERIFICATION_CANCEL -> {
onCancelReceived(event)
}
- EventType.KEY_VERIFICATION_ACCEPT -> {
+ EventType.KEY_VERIFICATION_ACCEPT -> {
onAcceptReceived(event)
}
- EventType.KEY_VERIFICATION_KEY -> {
+ EventType.KEY_VERIFICATION_KEY -> {
onKeyReceived(event)
}
- EventType.KEY_VERIFICATION_MAC -> {
+ EventType.KEY_VERIFICATION_MAC -> {
onMacReceived(event)
}
- EventType.KEY_VERIFICATION_READY -> {
+ EventType.KEY_VERIFICATION_READY -> {
onReadyReceived(event)
}
- EventType.KEY_VERIFICATION_DONE -> {
+ EventType.KEY_VERIFICATION_DONE -> {
onDoneReceived(event)
}
MessageType.MSGTYPE_VERIFICATION_REQUEST -> {
onRequestReceived(event)
}
- else -> {
+ else -> {
// ignore
}
}
@@ -163,7 +163,7 @@ internal class DefaultVerificationService @Inject constructor(
fun onRoomEvent(event: Event) {
cryptoCoroutineScope.launch(coroutineDispatchers.dmVerif) {
when (event.getClearType()) {
- EventType.KEY_VERIFICATION_START -> {
+ EventType.KEY_VERIFICATION_START -> {
onRoomStartRequestReceived(event)
}
EventType.KEY_VERIFICATION_CANCEL -> {
@@ -173,24 +173,24 @@ internal class DefaultVerificationService @Inject constructor(
EventType.KEY_VERIFICATION_ACCEPT -> {
onRoomAcceptReceived(event)
}
- EventType.KEY_VERIFICATION_KEY -> {
+ EventType.KEY_VERIFICATION_KEY -> {
onRoomKeyRequestReceived(event)
}
- EventType.KEY_VERIFICATION_MAC -> {
+ EventType.KEY_VERIFICATION_MAC -> {
onRoomMacReceived(event)
}
- EventType.KEY_VERIFICATION_READY -> {
+ EventType.KEY_VERIFICATION_READY -> {
onRoomReadyReceived(event)
}
- EventType.KEY_VERIFICATION_DONE -> {
+ EventType.KEY_VERIFICATION_DONE -> {
onRoomDoneReceived(event)
}
- EventType.MESSAGE -> {
+ EventType.MESSAGE -> {
if (MessageType.MSGTYPE_VERIFICATION_REQUEST == event.getClearContent().toModel()?.msgType) {
onRoomRequestReceived(event)
}
}
- else -> {
+ else -> {
// ignore
}
}
@@ -507,9 +507,9 @@ internal class DefaultVerificationService @Inject constructor(
}
when (startReq) {
- is ValidVerificationInfoStart.SasVerificationInfoStart -> {
+ is ValidVerificationInfoStart.SasVerificationInfoStart -> {
when (existing) {
- is SasVerificationTransaction -> {
+ is SasVerificationTransaction -> {
// should cancel both!
Timber.v("## SAS onStartRequestReceived - Request exist with same id ${startReq.transactionId}")
existing.cancel(CancelCode.UnexpectedMessage)
@@ -519,7 +519,7 @@ internal class DefaultVerificationService @Inject constructor(
is QrCodeVerificationTransaction -> {
// Nothing to do?
}
- null -> {
+ null -> {
getExistingTransactionsForUser(otherUserId)
?.filterIsInstance(SasVerificationTransaction::class.java)
?.takeIf { it.isNotEmpty() }
@@ -973,12 +973,12 @@ internal class DefaultVerificationService @Inject constructor(
}
return when {
- userId != otherUserId ->
+ userId != otherUserId ->
createQrCodeDataForDistinctUser(requestId, otherUserId)
crossSigningService.isCrossSigningVerified() ->
// This is a self verification and I am the old device (Osborne2)
createQrCodeDataForVerifiedDevice(requestId, otherDeviceId)
- else ->
+ else ->
// This is a self verification and I am the new device (Dynabook)
createQrCodeDataForUnVerifiedDevice(requestId)
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/SASDefaultVerificationTransaction.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/SASDefaultVerificationTransaction.kt
index d68f2c429d..1cbaff059a 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/SASDefaultVerificationTransaction.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/SASDefaultVerificationTransaction.kt
@@ -333,11 +333,11 @@ internal abstract class SASDefaultVerificationTransaction(
if (shortCodeBytes!!.size < 5) return null
return getDecimalCodeRepresentation(shortCodeBytes!!)
}
- SasMode.EMOJI -> {
+ SasMode.EMOJI -> {
if (shortCodeBytes!!.size < 6) return null
return getEmojiCodeRepresentation(shortCodeBytes!!).joinToString(" ") { it.emoji }
}
- else -> return null
+ else -> return null
}
}
@@ -362,8 +362,8 @@ internal abstract class SASDefaultVerificationTransaction(
private fun macUsingAgreedMethod(message: String, info: String): String? {
return when (accepted?.messageAuthenticationCode?.lowercase(Locale.ROOT)) {
SAS_MAC_SHA256_LONGKDF -> getSAS().calculateMacLongKdf(message, info)
- SAS_MAC_SHA256 -> getSAS().calculateMac(message, info)
- else -> null
+ SAS_MAC_SHA256 -> getSAS().calculateMac(message, info)
+ else -> null
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationEmoji.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationEmoji.kt
index eb1819fe6a..cff3591771 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationEmoji.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationEmoji.kt
@@ -20,69 +20,69 @@ import org.matrix.android.sdk.api.session.crypto.verification.EmojiRepresentatio
internal fun getEmojiForCode(code: Int): EmojiRepresentation {
return when (code % 64) {
- 0 -> EmojiRepresentation("🐶", R.string.verification_emoji_dog, R.drawable.ic_verification_dog)
- 1 -> EmojiRepresentation("🐱", R.string.verification_emoji_cat, R.drawable.ic_verification_cat)
- 2 -> EmojiRepresentation("🦁", R.string.verification_emoji_lion, R.drawable.ic_verification_lion)
- 3 -> EmojiRepresentation("🐎", R.string.verification_emoji_horse, R.drawable.ic_verification_horse)
- 4 -> EmojiRepresentation("🦄", R.string.verification_emoji_unicorn, R.drawable.ic_verification_unicorn)
- 5 -> EmojiRepresentation("🐷", R.string.verification_emoji_pig, R.drawable.ic_verification_pig)
- 6 -> EmojiRepresentation("🐘", R.string.verification_emoji_elephant, R.drawable.ic_verification_elephant)
- 7 -> EmojiRepresentation("🐰", R.string.verification_emoji_rabbit, R.drawable.ic_verification_rabbit)
- 8 -> EmojiRepresentation("🐼", R.string.verification_emoji_panda, R.drawable.ic_verification_panda)
- 9 -> EmojiRepresentation("🐓", R.string.verification_emoji_rooster, R.drawable.ic_verification_rooster)
- 10 -> EmojiRepresentation("🐧", R.string.verification_emoji_penguin, R.drawable.ic_verification_penguin)
- 11 -> EmojiRepresentation("🐢", R.string.verification_emoji_turtle, R.drawable.ic_verification_turtle)
- 12 -> EmojiRepresentation("🐟", R.string.verification_emoji_fish, R.drawable.ic_verification_fish)
- 13 -> EmojiRepresentation("🐙", R.string.verification_emoji_octopus, R.drawable.ic_verification_octopus)
- 14 -> EmojiRepresentation("🦋", R.string.verification_emoji_butterfly, R.drawable.ic_verification_butterfly)
- 15 -> EmojiRepresentation("🌷", R.string.verification_emoji_flower, R.drawable.ic_verification_flower)
- 16 -> EmojiRepresentation("🌳", R.string.verification_emoji_tree, R.drawable.ic_verification_tree)
- 17 -> EmojiRepresentation("🌵", R.string.verification_emoji_cactus, R.drawable.ic_verification_cactus)
- 18 -> EmojiRepresentation("🍄", R.string.verification_emoji_mushroom, R.drawable.ic_verification_mushroom)
- 19 -> EmojiRepresentation("🌏", R.string.verification_emoji_globe, R.drawable.ic_verification_globe)
- 20 -> EmojiRepresentation("🌙", R.string.verification_emoji_moon, R.drawable.ic_verification_moon)
- 21 -> EmojiRepresentation("☁️", R.string.verification_emoji_cloud, R.drawable.ic_verification_cloud)
- 22 -> EmojiRepresentation("🔥", R.string.verification_emoji_fire, R.drawable.ic_verification_fire)
- 23 -> EmojiRepresentation("🍌", R.string.verification_emoji_banana, R.drawable.ic_verification_banana)
- 24 -> EmojiRepresentation("🍎", R.string.verification_emoji_apple, R.drawable.ic_verification_apple)
- 25 -> EmojiRepresentation("🍓", R.string.verification_emoji_strawberry, R.drawable.ic_verification_strawberry)
- 26 -> EmojiRepresentation("🌽", R.string.verification_emoji_corn, R.drawable.ic_verification_corn)
- 27 -> EmojiRepresentation("🍕", R.string.verification_emoji_pizza, R.drawable.ic_verification_pizza)
- 28 -> EmojiRepresentation("🎂", R.string.verification_emoji_cake, R.drawable.ic_verification_cake)
- 29 -> EmojiRepresentation("❤️", R.string.verification_emoji_heart, R.drawable.ic_verification_heart)
- 30 -> EmojiRepresentation("🙂", R.string.verification_emoji_smiley, R.drawable.ic_verification_smiley)
- 31 -> EmojiRepresentation("🤖", R.string.verification_emoji_robot, R.drawable.ic_verification_robot)
- 32 -> EmojiRepresentation("🎩", R.string.verification_emoji_hat, R.drawable.ic_verification_hat)
- 33 -> EmojiRepresentation("👓", R.string.verification_emoji_glasses, R.drawable.ic_verification_glasses)
- 34 -> EmojiRepresentation("🔧", R.string.verification_emoji_spanner, R.drawable.ic_verification_spanner)
- 35 -> EmojiRepresentation("🎅", R.string.verification_emoji_santa, R.drawable.ic_verification_santa)
- 36 -> EmojiRepresentation("👍", R.string.verification_emoji_thumbs_up, R.drawable.ic_verification_thumbs_up)
- 37 -> EmojiRepresentation("☂️", R.string.verification_emoji_umbrella, R.drawable.ic_verification_umbrella)
- 38 -> EmojiRepresentation("⌛", R.string.verification_emoji_hourglass, R.drawable.ic_verification_hourglass)
- 39 -> EmojiRepresentation("⏰", R.string.verification_emoji_clock, R.drawable.ic_verification_clock)
- 40 -> EmojiRepresentation("🎁", R.string.verification_emoji_gift, R.drawable.ic_verification_gift)
- 41 -> EmojiRepresentation("💡", R.string.verification_emoji_light_bulb, R.drawable.ic_verification_light_bulb)
- 42 -> EmojiRepresentation("📕", R.string.verification_emoji_book, R.drawable.ic_verification_book)
- 43 -> EmojiRepresentation("✏️", R.string.verification_emoji_pencil, R.drawable.ic_verification_pencil)
- 44 -> EmojiRepresentation("📎", R.string.verification_emoji_paperclip, R.drawable.ic_verification_paperclip)
- 45 -> EmojiRepresentation("✂️", R.string.verification_emoji_scissors, R.drawable.ic_verification_scissors)
- 46 -> EmojiRepresentation("🔒", R.string.verification_emoji_lock, R.drawable.ic_verification_lock)
- 47 -> EmojiRepresentation("🔑", R.string.verification_emoji_key, R.drawable.ic_verification_key)
- 48 -> EmojiRepresentation("🔨", R.string.verification_emoji_hammer, R.drawable.ic_verification_hammer)
- 49 -> EmojiRepresentation("☎️", R.string.verification_emoji_telephone, R.drawable.ic_verification_phone)
- 50 -> EmojiRepresentation("🏁", R.string.verification_emoji_flag, R.drawable.ic_verification_flag)
- 51 -> EmojiRepresentation("🚂", R.string.verification_emoji_train, R.drawable.ic_verification_train)
- 52 -> EmojiRepresentation("🚲", R.string.verification_emoji_bicycle, R.drawable.ic_verification_bicycle)
- 53 -> EmojiRepresentation("✈️", R.string.verification_emoji_aeroplane, R.drawable.ic_verification_aeroplane)
- 54 -> EmojiRepresentation("🚀", R.string.verification_emoji_rocket, R.drawable.ic_verification_rocket)
- 55 -> EmojiRepresentation("🏆", R.string.verification_emoji_trophy, R.drawable.ic_verification_trophy)
- 56 -> EmojiRepresentation("⚽", R.string.verification_emoji_ball, R.drawable.ic_verification_ball)
- 57 -> EmojiRepresentation("🎸", R.string.verification_emoji_guitar, R.drawable.ic_verification_guitar)
- 58 -> EmojiRepresentation("🎺", R.string.verification_emoji_trumpet, R.drawable.ic_verification_trumpet)
- 59 -> EmojiRepresentation("🔔", R.string.verification_emoji_bell, R.drawable.ic_verification_bell)
- 60 -> EmojiRepresentation("⚓", R.string.verification_emoji_anchor, R.drawable.ic_verification_anchor)
- 61 -> EmojiRepresentation("🎧", R.string.verification_emoji_headphones, R.drawable.ic_verification_headphones)
- 62 -> EmojiRepresentation("📁", R.string.verification_emoji_folder, R.drawable.ic_verification_folder)
+ 0 -> EmojiRepresentation("🐶", R.string.verification_emoji_dog, R.drawable.ic_verification_dog)
+ 1 -> EmojiRepresentation("🐱", R.string.verification_emoji_cat, R.drawable.ic_verification_cat)
+ 2 -> EmojiRepresentation("🦁", R.string.verification_emoji_lion, R.drawable.ic_verification_lion)
+ 3 -> EmojiRepresentation("🐎", R.string.verification_emoji_horse, R.drawable.ic_verification_horse)
+ 4 -> EmojiRepresentation("🦄", R.string.verification_emoji_unicorn, R.drawable.ic_verification_unicorn)
+ 5 -> EmojiRepresentation("🐷", R.string.verification_emoji_pig, R.drawable.ic_verification_pig)
+ 6 -> EmojiRepresentation("🐘", R.string.verification_emoji_elephant, R.drawable.ic_verification_elephant)
+ 7 -> EmojiRepresentation("🐰", R.string.verification_emoji_rabbit, R.drawable.ic_verification_rabbit)
+ 8 -> EmojiRepresentation("🐼", R.string.verification_emoji_panda, R.drawable.ic_verification_panda)
+ 9 -> EmojiRepresentation("🐓", R.string.verification_emoji_rooster, R.drawable.ic_verification_rooster)
+ 10 -> EmojiRepresentation("🐧", R.string.verification_emoji_penguin, R.drawable.ic_verification_penguin)
+ 11 -> EmojiRepresentation("🐢", R.string.verification_emoji_turtle, R.drawable.ic_verification_turtle)
+ 12 -> EmojiRepresentation("🐟", R.string.verification_emoji_fish, R.drawable.ic_verification_fish)
+ 13 -> EmojiRepresentation("🐙", R.string.verification_emoji_octopus, R.drawable.ic_verification_octopus)
+ 14 -> EmojiRepresentation("🦋", R.string.verification_emoji_butterfly, R.drawable.ic_verification_butterfly)
+ 15 -> EmojiRepresentation("🌷", R.string.verification_emoji_flower, R.drawable.ic_verification_flower)
+ 16 -> EmojiRepresentation("🌳", R.string.verification_emoji_tree, R.drawable.ic_verification_tree)
+ 17 -> EmojiRepresentation("🌵", R.string.verification_emoji_cactus, R.drawable.ic_verification_cactus)
+ 18 -> EmojiRepresentation("🍄", R.string.verification_emoji_mushroom, R.drawable.ic_verification_mushroom)
+ 19 -> EmojiRepresentation("🌏", R.string.verification_emoji_globe, R.drawable.ic_verification_globe)
+ 20 -> EmojiRepresentation("🌙", R.string.verification_emoji_moon, R.drawable.ic_verification_moon)
+ 21 -> EmojiRepresentation("☁️", R.string.verification_emoji_cloud, R.drawable.ic_verification_cloud)
+ 22 -> EmojiRepresentation("🔥", R.string.verification_emoji_fire, R.drawable.ic_verification_fire)
+ 23 -> EmojiRepresentation("🍌", R.string.verification_emoji_banana, R.drawable.ic_verification_banana)
+ 24 -> EmojiRepresentation("🍎", R.string.verification_emoji_apple, R.drawable.ic_verification_apple)
+ 25 -> EmojiRepresentation("🍓", R.string.verification_emoji_strawberry, R.drawable.ic_verification_strawberry)
+ 26 -> EmojiRepresentation("🌽", R.string.verification_emoji_corn, R.drawable.ic_verification_corn)
+ 27 -> EmojiRepresentation("🍕", R.string.verification_emoji_pizza, R.drawable.ic_verification_pizza)
+ 28 -> EmojiRepresentation("🎂", R.string.verification_emoji_cake, R.drawable.ic_verification_cake)
+ 29 -> EmojiRepresentation("❤️", R.string.verification_emoji_heart, R.drawable.ic_verification_heart)
+ 30 -> EmojiRepresentation("🙂", R.string.verification_emoji_smiley, R.drawable.ic_verification_smiley)
+ 31 -> EmojiRepresentation("🤖", R.string.verification_emoji_robot, R.drawable.ic_verification_robot)
+ 32 -> EmojiRepresentation("🎩", R.string.verification_emoji_hat, R.drawable.ic_verification_hat)
+ 33 -> EmojiRepresentation("👓", R.string.verification_emoji_glasses, R.drawable.ic_verification_glasses)
+ 34 -> EmojiRepresentation("🔧", R.string.verification_emoji_spanner, R.drawable.ic_verification_spanner)
+ 35 -> EmojiRepresentation("🎅", R.string.verification_emoji_santa, R.drawable.ic_verification_santa)
+ 36 -> EmojiRepresentation("👍", R.string.verification_emoji_thumbs_up, R.drawable.ic_verification_thumbs_up)
+ 37 -> EmojiRepresentation("☂️", R.string.verification_emoji_umbrella, R.drawable.ic_verification_umbrella)
+ 38 -> EmojiRepresentation("⌛", R.string.verification_emoji_hourglass, R.drawable.ic_verification_hourglass)
+ 39 -> EmojiRepresentation("⏰", R.string.verification_emoji_clock, R.drawable.ic_verification_clock)
+ 40 -> EmojiRepresentation("🎁", R.string.verification_emoji_gift, R.drawable.ic_verification_gift)
+ 41 -> EmojiRepresentation("💡", R.string.verification_emoji_light_bulb, R.drawable.ic_verification_light_bulb)
+ 42 -> EmojiRepresentation("📕", R.string.verification_emoji_book, R.drawable.ic_verification_book)
+ 43 -> EmojiRepresentation("✏️", R.string.verification_emoji_pencil, R.drawable.ic_verification_pencil)
+ 44 -> EmojiRepresentation("📎", R.string.verification_emoji_paperclip, R.drawable.ic_verification_paperclip)
+ 45 -> EmojiRepresentation("✂️", R.string.verification_emoji_scissors, R.drawable.ic_verification_scissors)
+ 46 -> EmojiRepresentation("🔒", R.string.verification_emoji_lock, R.drawable.ic_verification_lock)
+ 47 -> EmojiRepresentation("🔑", R.string.verification_emoji_key, R.drawable.ic_verification_key)
+ 48 -> EmojiRepresentation("🔨", R.string.verification_emoji_hammer, R.drawable.ic_verification_hammer)
+ 49 -> EmojiRepresentation("☎️", R.string.verification_emoji_telephone, R.drawable.ic_verification_phone)
+ 50 -> EmojiRepresentation("🏁", R.string.verification_emoji_flag, R.drawable.ic_verification_flag)
+ 51 -> EmojiRepresentation("🚂", R.string.verification_emoji_train, R.drawable.ic_verification_train)
+ 52 -> EmojiRepresentation("🚲", R.string.verification_emoji_bicycle, R.drawable.ic_verification_bicycle)
+ 53 -> EmojiRepresentation("✈️", R.string.verification_emoji_aeroplane, R.drawable.ic_verification_aeroplane)
+ 54 -> EmojiRepresentation("🚀", R.string.verification_emoji_rocket, R.drawable.ic_verification_rocket)
+ 55 -> EmojiRepresentation("🏆", R.string.verification_emoji_trophy, R.drawable.ic_verification_trophy)
+ 56 -> EmojiRepresentation("⚽", R.string.verification_emoji_ball, R.drawable.ic_verification_ball)
+ 57 -> EmojiRepresentation("🎸", R.string.verification_emoji_guitar, R.drawable.ic_verification_guitar)
+ 58 -> EmojiRepresentation("🎺", R.string.verification_emoji_trumpet, R.drawable.ic_verification_trumpet)
+ 59 -> EmojiRepresentation("🔔", R.string.verification_emoji_bell, R.drawable.ic_verification_bell)
+ 60 -> EmojiRepresentation("⚓", R.string.verification_emoji_anchor, R.drawable.ic_verification_anchor)
+ 61 -> EmojiRepresentation("🎧", R.string.verification_emoji_headphones, R.drawable.ic_verification_headphones)
+ 62 -> EmojiRepresentation("📁", R.string.verification_emoji_folder, R.drawable.ic_verification_folder)
/* 63 */ else -> EmojiRepresentation("📌", R.string.verification_emoji_pin, R.drawable.ic_verification_pin)
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationInfoStart.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationInfoStart.kt
index 991470a848..66591fe00f 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationInfoStart.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationInfoStart.kt
@@ -68,7 +68,7 @@ internal interface VerificationInfoStart : VerificationInfo {
+ VERIFICATION_METHOD_SAS -> {
val validKeyAgreementProtocols = keyAgreementProtocols?.takeIf { it.isNotEmpty() } ?: return null
val validHashes = hashes?.takeIf { it.contains("sha256") } ?: return null
val validMessageAuthenticationCodes = messageAuthenticationCodes
@@ -98,7 +98,7 @@ internal interface VerificationInfoStart : VerificationInfo null
+ else -> null
}
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationMessageProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationMessageProcessor.kt
index 303b6c5839..8a805a5588 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationMessageProcessor.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationMessageProcessor.kt
@@ -62,8 +62,8 @@ internal class VerificationMessageProcessor @Inject constructor(
// If the request is in the future by more than 5 minutes or more than 10 minutes in the past,
// the message should be ignored by the receiver.
- if (event.ageLocalTs != null && !VerificationService.isValidRequest(event.ageLocalTs, clock.epochMillis())) return Unit.also {
- Timber.d("## SAS Verification live observer: msgId: ${event.eventId} is outdated age:$event.ageLocalTs ms")
+ if (!VerificationService.isValidRequest(event.ageLocalTs, clock.epochMillis())) return Unit.also {
+ Timber.d("## SAS Verification live observer: msgId: ${event.eventId} is outdated age:${event.ageLocalTs} ms")
}
Timber.v("## SAS Verification live observer: received msgId: ${event.eventId} type: ${event.getClearType()}")
@@ -131,7 +131,7 @@ internal class VerificationMessageProcessor @Inject constructor(
EventType.KEY_VERIFICATION_DONE -> {
verificationService.onRoomEvent(event)
}
- EventType.MESSAGE -> {
+ EventType.MESSAGE -> {
if (MessageType.MSGTYPE_VERIFICATION_REQUEST == event.getClearContent().toModel()?.msgType) {
verificationService.onRoomRequestReceived(event)
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationTransportToDevice.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationTransportToDevice.kt
index 861a7a3a77..23a75d2bb3 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationTransportToDevice.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationTransportToDevice.kt
@@ -76,12 +76,12 @@ internal class VerificationTransportToDevice(
.configureWith(SendToDeviceTask.Params(MessageType.MSGTYPE_VERIFICATION_REQUEST, contentMap)) {
this.callback = object : MatrixCallback {
override fun onSuccess(data: Unit) {
- Timber.v("## verification [$tx.transactionId] send toDevice request success")
+ Timber.v("## verification [${tx?.transactionId}] send toDevice request success")
callback.invoke(localId, validKeyReq)
}
override fun onFailure(failure: Throwable) {
- Timber.e("## verification [$tx.transactionId] failed to send toDevice request")
+ Timber.e("## verification [${tx?.transactionId}] failed to send toDevice request")
}
}
}
@@ -103,12 +103,12 @@ internal class VerificationTransportToDevice(
.configureWith(SendToDeviceTask.Params(EventType.KEY_VERIFICATION_READY, contentMap)) {
this.callback = object : MatrixCallback {
override fun onSuccess(data: Unit) {
- Timber.v("## verification [$tx.transactionId] send toDevice request success")
+ Timber.v("## verification [${tx?.transactionId}] send toDevice request success")
callback?.invoke()
}
override fun onFailure(failure: Throwable) {
- Timber.e("## verification [$tx.transactionId] failed to send toDevice request")
+ Timber.e("## verification [${tx?.transactionId}] failed to send toDevice request")
}
}
}
@@ -136,7 +136,7 @@ internal class VerificationTransportToDevice(
.configureWith(SendToDeviceTask.Params(type, contentMap)) {
this.callback = object : MatrixCallback {
override fun onSuccess(data: Unit) {
- Timber.v("## SAS verification [$tx.transactionId] toDevice type '$type' success.")
+ Timber.v("## SAS verification [${tx.transactionId}] toDevice type '$type' success.")
if (onDone != null) {
onDone()
} else {
@@ -149,7 +149,7 @@ internal class VerificationTransportToDevice(
}
override fun onFailure(failure: Throwable) {
- Timber.e("## SAS verification [$tx.transactionId] failed to send toDevice in state : $tx.state")
+ Timber.e("## SAS verification [${tx.transactionId}] failed to send toDevice in state : ${tx.state}")
tx.cancel(onErrorReason)
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/DefaultQrCodeVerificationTransaction.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/DefaultQrCodeVerificationTransaction.kt
index b1ad4d87b6..5b1a4752f1 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/DefaultQrCodeVerificationTransaction.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/DefaultQrCodeVerificationTransaction.kt
@@ -84,7 +84,7 @@ internal class DefaultQrCodeVerificationTransaction(
// Perform some checks
if (otherQrCodeData.transactionId != transactionId) {
Timber.d("## Verification QR: Invalid transaction actual ${otherQrCodeData.transactionId} expected:$transactionId")
- cancel(CancelCode.QrCodeInvalid)
+ cancel(CancelCode.UnknownTransaction)
return
}
@@ -94,7 +94,7 @@ internal class DefaultQrCodeVerificationTransaction(
// Check the other device view of my MSK
when (otherQrCodeData) {
- is QrCodeData.VerifyingAnotherUser -> {
+ is QrCodeData.VerifyingAnotherUser -> {
// key2 (aka otherUserMasterCrossSigningPublicKey) is what the one displaying the QR code (other user) think my MSK is.
// Let's check that it's correct
// If not -> Cancel
@@ -104,7 +104,7 @@ internal class DefaultQrCodeVerificationTransaction(
return
} else Unit
}
- is QrCodeData.SelfVerifyingMasterKeyTrusted -> {
+ is QrCodeData.SelfVerifyingMasterKeyTrusted -> {
// key1 (aka userMasterCrossSigningPublicKey) is the session displaying the QR code view of our MSK.
// Let's check that I see the same MSK
// If not -> Cancel
@@ -135,7 +135,7 @@ internal class DefaultQrCodeVerificationTransaction(
// Let's now check the other user/device key material
when (otherQrCodeData) {
- is QrCodeData.VerifyingAnotherUser -> {
+ is QrCodeData.VerifyingAnotherUser -> {
// key1(aka userMasterCrossSigningPublicKey) is the MSK of the one displaying the QR code (i.e other user)
// Let's check that it matches what I think it should be
if (otherQrCodeData.userMasterCrossSigningPublicKey
@@ -149,7 +149,7 @@ internal class DefaultQrCodeVerificationTransaction(
Unit
}
}
- is QrCodeData.SelfVerifyingMasterKeyTrusted -> {
+ is QrCodeData.SelfVerifyingMasterKeyTrusted -> {
// key2 (aka otherDeviceKey) is my current device key in POV of the one displaying the QR code (i.e other device)
// Let's check that it's correct
if (otherQrCodeData.otherDeviceKey
@@ -259,11 +259,11 @@ internal class DefaultQrCodeVerificationTransaction(
override fun otherUserScannedMyQrCode() {
when (qrCodeData) {
- is QrCodeData.VerifyingAnotherUser -> {
+ is QrCodeData.VerifyingAnotherUser -> {
// Alice telling Bob that the code was scanned successfully is sufficient for Bob to trust Alice's key,
trust(true, emptyList(), false)
}
- is QrCodeData.SelfVerifyingMasterKeyTrusted -> {
+ is QrCodeData.SelfVerifyingMasterKeyTrusted -> {
// I now know that I have the correct device key for other session,
// and can sign it with the self-signing key and upload the signature
trust(false, listOf(otherDeviceId ?: ""), false)
@@ -272,7 +272,7 @@ internal class DefaultQrCodeVerificationTransaction(
// I now know that i can trust my MSK
trust(true, emptyList(), true)
}
- null -> Unit
+ null -> Unit
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/Extensions.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/Extensions.kt
index b80c29c244..a0202485d6 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/Extensions.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/Extensions.kt
@@ -36,8 +36,8 @@ internal fun QrCodeData.toEncodedString(): String {
// Mode
result += when (this) {
- is QrCodeData.VerifyingAnotherUser -> 0
- is QrCodeData.SelfVerifyingMasterKeyTrusted -> 1
+ is QrCodeData.VerifyingAnotherUser -> 0
+ is QrCodeData.SelfVerifyingMasterKeyTrusted -> 1
is QrCodeData.SelfVerifyingMasterKeyNotTrusted -> 2
}.toByte()
@@ -119,9 +119,9 @@ internal fun String.toQrCodeData(): QrCodeData? {
val secret = byteArray.copyOfRange(cursor, byteArray.size).toBase64NoPadding()
return when (mode) {
- 0 -> QrCodeData.VerifyingAnotherUser(transactionId, key1, key2, secret)
- 1 -> QrCodeData.SelfVerifyingMasterKeyTrusted(transactionId, key1, key2, secret)
- 2 -> QrCodeData.SelfVerifyingMasterKeyNotTrusted(transactionId, key1, key2, secret)
+ 0 -> QrCodeData.VerifyingAnotherUser(transactionId, key1, key2, secret)
+ 1 -> QrCodeData.SelfVerifyingMasterKeyTrusted(transactionId, key1, key2, secret)
+ 2 -> QrCodeData.SelfVerifyingMasterKeyNotTrusted(transactionId, key1, key2, secret)
else -> null
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/EventInsertLiveObserver.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/EventInsertLiveObserver.kt
index 4434347db1..d1ca4f48a6 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/EventInsertLiveObserver.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/EventInsertLiveObserver.kt
@@ -19,10 +19,9 @@ package org.matrix.android.sdk.internal.database
import com.zhuinden.monarchy.Monarchy
import io.realm.RealmConfiguration
import io.realm.RealmResults
-import kotlinx.coroutines.flow.MutableSharedFlow
-import kotlinx.coroutines.flow.launchIn
-import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
+import kotlinx.coroutines.sync.Mutex
+import kotlinx.coroutines.sync.withLock
import org.matrix.android.sdk.internal.database.mapper.asDomain
import org.matrix.android.sdk.internal.database.model.EventEntity
import org.matrix.android.sdk.internal.database.model.EventInsertEntity
@@ -39,65 +38,58 @@ internal class EventInsertLiveObserver @Inject constructor(
) :
RealmLiveEntityObserver(realmConfiguration) {
+ private val lock = Mutex()
+
override val query = Monarchy.Query {
it.where(EventInsertEntity::class.java).equalTo(EventInsertEntityFields.CAN_BE_PROCESSED, true)
}
- private val onResultsChangedFlow = MutableSharedFlow>()
-
- 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")
- results.forEach {
- if (shouldProcess(it)) {
- // don't use copy from realm over there
- val copiedEvent = EventInsertEntity(
- eventId = it.eventId,
- eventType = it.eventType
- ).apply {
- insertType = it.insertType
+ observerScope.launch {
+ lock.withLock {
+ if (!results.isLoaded || results.isEmpty()) {
+ return@withLock
}
- filteredEvents.add(copiedEvent)
+ val idsToDeleteAfterProcess = ArrayList()
+ val filteredEvents = ArrayList(results.size)
+ Timber.v("EventInsertEntity updated with ${results.size} results in db")
+ results.forEach {
+ if (shouldProcess(it)) {
+ // don't use copy from realm over there
+ val copiedEvent = EventInsertEntity(
+ eventId = it.eventId,
+ eventType = it.eventType
+ ).apply {
+ insertType = it.insertType
+ }
+ filteredEvents.add(copiedEvent)
+ }
+ idsToDeleteAfterProcess.add(it.eventId)
+ }
+ 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() }
}
- idsToDeleteAfterProcess.add(it.eventId)
}
-
- awaitTransaction(realmConfiguration) { realm ->
- Timber.v("##Transaction: There are ${filteredEvents.size} events to process ")
- filteredEvents.forEach { eventInsert ->
- val eventId = eventInsert.eventId
- val event = EventEntity.where(realm, eventId).findFirst()
- if (event == null) {
- Timber.v("Event $eventId not found")
- return@forEach
- }
- val 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() }
}
private fun shouldProcess(eventInsertEntity: EventInsertEntity): Boolean {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmKeysUtils.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmKeysUtils.kt
index b3a039d119..86355ceaa8 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmKeysUtils.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmKeysUtils.kt
@@ -21,7 +21,7 @@ import androidx.core.content.edit
import io.realm.Realm
import io.realm.RealmConfiguration
import org.matrix.android.sdk.BuildConfig
-import org.matrix.android.sdk.internal.session.securestorage.SecretStoringUtils
+import org.matrix.android.sdk.api.securestorage.SecretStoringUtils
import timber.log.Timber
import java.security.SecureRandom
import javax.inject.Inject
@@ -40,7 +40,7 @@ import javax.inject.Inject
*/
internal class RealmKeysUtils @Inject constructor(
context: Context,
- private val secretStoringUtils: SecretStoringUtils
+ private val secretStoringUtils: SecretStoringUtils,
) {
private val rng = SecureRandom()
@@ -71,7 +71,7 @@ internal class RealmKeysUtils @Inject constructor(
private fun createAndSaveKeyForDatabase(alias: String): ByteArray {
val key = generateKeyForRealm()
val encodedKey = Base64.encodeToString(key, Base64.NO_PADDING)
- val toStore = secretStoringUtils.securelyStoreString(encodedKey, alias)
+ val toStore = secretStoringUtils.securelyStoreBytes(encodedKey.toByteArray(), alias)
sharedPreferences.edit {
putString("${ENCRYPTED_KEY_PREFIX}_$alias", Base64.encodeToString(toStore, Base64.NO_PADDING))
}
@@ -85,7 +85,7 @@ internal class RealmKeysUtils @Inject constructor(
private fun extractKeyForDatabase(alias: String): ByteArray {
val encryptedB64 = sharedPreferences.getString("${ENCRYPTED_KEY_PREFIX}_$alias", null)
val encryptedKey = Base64.decode(encryptedB64, Base64.NO_PADDING)
- val b64 = secretStoringUtils.loadSecureSecret(encryptedKey, alias)
+ val b64 = secretStoringUtils.loadSecureSecretBytes(encryptedKey, alias)
return Base64.decode(b64, Base64.NO_PADDING)
}
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 592461f927..b733aa6fc0 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
@@ -17,7 +17,6 @@
package org.matrix.android.sdk.internal.database
import io.realm.DynamicRealm
-import io.realm.RealmMigration
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo001
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo002
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo003
@@ -47,13 +46,22 @@ import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo026
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo027
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo028
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo029
+import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo030
+import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo031
+import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo032
+import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo033
+import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo034
+import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo035
import org.matrix.android.sdk.internal.util.Normalizer
-import timber.log.Timber
+import org.matrix.android.sdk.internal.util.database.MatrixRealmMigration
import javax.inject.Inject
internal class RealmSessionStoreMigration @Inject constructor(
private val normalizer: Normalizer
-) : RealmMigration {
+) : MatrixRealmMigration(
+ dbName = "Session",
+ schemaVersion = 35L,
+) {
/**
* Forces all RealmSessionStoreMigration instances to be equal.
* Avoids Realm throwing when multiple instances of the migration are set.
@@ -61,11 +69,7 @@ internal class RealmSessionStoreMigration @Inject constructor(
override fun equals(other: Any?) = other is RealmSessionStoreMigration
override fun hashCode() = 1000
- val schemaVersion = 29L
-
- override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) {
- Timber.d("Migrating Realm Session from $oldVersion to $newVersion")
-
+ override fun doMigrate(realm: DynamicRealm, oldVersion: Long) {
if (oldVersion < 1) MigrateSessionTo001(realm).perform()
if (oldVersion < 2) MigrateSessionTo002(realm).perform()
if (oldVersion < 3) MigrateSessionTo003(realm).perform()
@@ -95,5 +99,11 @@ internal class RealmSessionStoreMigration @Inject constructor(
if (oldVersion < 27) MigrateSessionTo027(realm).perform()
if (oldVersion < 28) MigrateSessionTo028(realm).perform()
if (oldVersion < 29) MigrateSessionTo029(realm).perform()
+ if (oldVersion < 30) MigrateSessionTo030(realm).perform()
+ if (oldVersion < 31) MigrateSessionTo031(realm).perform()
+ if (oldVersion < 32) MigrateSessionTo032(realm).perform()
+ if (oldVersion < 33) MigrateSessionTo033(realm).perform()
+ if (oldVersion < 34) MigrateSessionTo034(realm).perform()
+ if (oldVersion < 35) MigrateSessionTo035(realm).perform()
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/SessionRealmConfigurationFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/SessionRealmConfigurationFactory.kt
index 949dd5daa1..5a0fd74bc0 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/SessionRealmConfigurationFactory.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/SessionRealmConfigurationFactory.kt
@@ -93,7 +93,7 @@ internal class SessionRealmConfigurationFactory @Inject constructor(
return
}
- listOf(REALM_NAME, "$REALM_NAME.lock", "$REALM_NAME.note", "$REALM_NAME.management").forEach { file ->
+ listOf(REALM_NAME, "${REALM_NAME}.lock", "${REALM_NAME}.note", "${REALM_NAME}.management").forEach { file ->
try {
File(directory, file).deleteRecursively()
} catch (e: Exception) {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ChunkEntityHelper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ChunkEntityHelper.kt
index efcbc9de12..221abe0df5 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ChunkEntityHelper.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ChunkEntityHelper.kt
@@ -17,9 +17,12 @@
package org.matrix.android.sdk.internal.database.helper
import io.realm.Realm
-import io.realm.Sort
import io.realm.kotlin.createObject
+import org.matrix.android.sdk.api.session.events.model.content.EncryptedEventContent
+import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.room.model.RoomMemberContent
+import org.matrix.android.sdk.internal.crypto.model.SessionInfo
+import org.matrix.android.sdk.internal.database.mapper.asDomain
import org.matrix.android.sdk.internal.database.model.ChunkEntity
import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntityFields
import org.matrix.android.sdk.internal.database.model.EventAnnotationsSummaryEntity
@@ -32,34 +35,12 @@ import org.matrix.android.sdk.internal.database.model.RoomMemberSummaryEntityFie
import org.matrix.android.sdk.internal.database.model.TimelineEventEntity
import org.matrix.android.sdk.internal.database.model.TimelineEventEntityFields
import org.matrix.android.sdk.internal.database.query.find
+import org.matrix.android.sdk.internal.database.query.findLastForwardChunkOfRoom
import org.matrix.android.sdk.internal.database.query.getOrCreate
import org.matrix.android.sdk.internal.database.query.where
-import org.matrix.android.sdk.internal.database.query.whereRoomId
-import org.matrix.android.sdk.internal.extensions.assertIsManaged
import org.matrix.android.sdk.internal.session.room.timeline.PaginationDirection
import timber.log.Timber
-internal fun ChunkEntity.merge(roomId: String, chunkToMerge: ChunkEntity, direction: PaginationDirection) {
- assertIsManaged()
- val localRealm = this.realm
- val eventsToMerge: List
- if (direction == PaginationDirection.FORWARDS) {
- this.nextToken = chunkToMerge.nextToken
- this.isLastForward = chunkToMerge.isLastForward
- eventsToMerge = chunkToMerge.timelineEvents.sort(TimelineEventEntityFields.DISPLAY_INDEX, Sort.ASCENDING)
- } else {
- this.prevToken = chunkToMerge.prevToken
- this.isLastBackward = chunkToMerge.isLastBackward
- eventsToMerge = chunkToMerge.timelineEvents.sort(TimelineEventEntityFields.DISPLAY_INDEX, Sort.DESCENDING)
- }
- chunkToMerge.stateEvents.forEach { stateEvent ->
- addStateEvent(roomId, stateEvent, direction)
- }
- eventsToMerge.forEach {
- addTimelineEventFromMerge(localRealm, it, direction)
- }
-}
-
internal fun ChunkEntity.addStateEvent(roomId: String, stateEvent: EventEntity, direction: PaginationDirection) {
if (direction == PaginationDirection.BACKWARDS) {
Timber.v("We don't keep chunk state events when paginating backward")
@@ -144,40 +125,6 @@ internal fun computeIsUnique(
}
}
-private fun ChunkEntity.addTimelineEventFromMerge(realm: Realm, timelineEventEntity: TimelineEventEntity, direction: PaginationDirection) {
- val eventId = timelineEventEntity.eventId
- if (timelineEvents.find(eventId) != null) {
- return
- }
- val displayIndex = nextDisplayIndex(direction)
- val localId = TimelineEventEntity.nextId(realm)
- val copied = realm.createObject().apply {
- this.localId = localId
- this.root = timelineEventEntity.root
- this.eventId = timelineEventEntity.eventId
- this.roomId = timelineEventEntity.roomId
- this.annotations = timelineEventEntity.annotations
- this.readReceipts = timelineEventEntity.readReceipts
- this.displayIndex = displayIndex
- this.senderAvatar = timelineEventEntity.senderAvatar
- this.senderName = timelineEventEntity.senderName
- this.isUniqueDisplayName = timelineEventEntity.isUniqueDisplayName
- }
- handleThreadSummary(realm, eventId, copied)
- timelineEvents.add(copied)
-}
-
-/**
- * Upon copy of the timeline events we should update the latestMessage TimelineEventEntity with the new one.
- */
-private fun handleThreadSummary(realm: Realm, oldEventId: String, newTimelineEventEntity: TimelineEventEntity) {
- EventEntity
- .whereRoomId(realm, newTimelineEventEntity.roomId)
- .equalTo(EventEntityFields.IS_ROOT_THREAD, true)
- .equalTo(EventEntityFields.THREAD_SUMMARY_LATEST_MESSAGE.EVENT_ID, oldEventId)
- .findFirst()?.threadSummaryLatestMessage = newTimelineEventEntity
-}
-
private fun handleReadReceipts(realm: Realm, roomId: String, eventEntity: EventEntity, senderId: String): ReadReceiptsSummaryEntity {
val readReceiptsSummaryEntity = ReadReceiptsSummaryEntity.where(realm, eventEntity.eventId).findFirst()
?: realm.createObject(eventEntity.eventId).apply {
@@ -201,7 +148,7 @@ private fun handleReadReceipts(realm: Realm, roomId: String, eventEntity: EventE
internal fun ChunkEntity.nextDisplayIndex(direction: PaginationDirection): Int {
return when (direction) {
- PaginationDirection.FORWARDS -> {
+ PaginationDirection.FORWARDS -> {
(timelineEvents.where().max(TimelineEventEntityFields.DISPLAY_INDEX)?.toInt() ?: 0) + 1
}
PaginationDirection.BACKWARDS -> {
@@ -238,3 +185,12 @@ internal fun ChunkEntity.isMoreRecentThan(chunkToCheck: ChunkEntity): Boolean {
// We don't know, so we assume it's false
return false
}
+
+internal fun ChunkEntity.Companion.findLatestSessionInfo(realm: Realm, roomId: String): Set? =
+ ChunkEntity.findLastForwardChunkOfRoom(realm, roomId)?.timelineEvents?.mapNotNull { timelineEvent ->
+ timelineEvent?.root?.asDomain()?.content?.toModel()?.let { content ->
+ content.sessionId ?: return@mapNotNull null
+ content.senderKey ?: return@mapNotNull null
+ SessionInfo(content.sessionId, content.senderKey)
+ }
+ }?.toSet()
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 ebe8de7841..0a6d4bf833 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
@@ -181,7 +181,7 @@ internal fun ThreadSummaryEntity.Companion.createOrUpdate(
roomEntity.addIfNecessary(threadSummary)
}
- ThreadSummaryUpdateType.ADD -> {
+ ThreadSummaryUpdateType.ADD -> {
val rootThreadEventId = threadEventEntity?.rootThreadEventId ?: return
Timber.i("###THREADS ThreadSummaryHelper ADD for root eventId:$rootThreadEventId")
@@ -271,7 +271,7 @@ private fun HashMap.addSenderState(realm: Realm, roo
* Create an EventEntity for the root thread event or get an existing one.
*/
private fun createEventEntity(realm: Realm, roomId: String, event: Event, currentTimeMillis: Long): EventEntity {
- val ageLocalTs = event.unsignedData?.age?.let { currentTimeMillis - it }
+ val ageLocalTs = currentTimeMillis - (event.unsignedData?.age ?: 0)
return event.toEntity(roomId, SendState.SYNCED, ageLocalTs).copyToRealmOrIgnore(realm, EventInsertType.PAGINATION)
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/DraftMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/DraftMapper.kt
index a00a2a8ee1..4cf2ef6723 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/DraftMapper.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/DraftMapper.kt
@@ -27,21 +27,21 @@ internal object DraftMapper {
fun map(entity: DraftEntity): UserDraft {
return when (entity.draftMode) {
DraftEntity.MODE_REGULAR -> UserDraft.Regular(entity.content)
- DraftEntity.MODE_EDIT -> UserDraft.Edit(entity.linkedEventId, entity.content)
- DraftEntity.MODE_QUOTE -> UserDraft.Quote(entity.linkedEventId, entity.content)
- DraftEntity.MODE_REPLY -> UserDraft.Reply(entity.linkedEventId, entity.content)
- DraftEntity.MODE_VOICE -> UserDraft.Voice(entity.content)
- else -> null
+ DraftEntity.MODE_EDIT -> UserDraft.Edit(entity.linkedEventId, entity.content)
+ DraftEntity.MODE_QUOTE -> UserDraft.Quote(entity.linkedEventId, entity.content)
+ DraftEntity.MODE_REPLY -> UserDraft.Reply(entity.linkedEventId, entity.content)
+ DraftEntity.MODE_VOICE -> UserDraft.Voice(entity.content)
+ else -> null
} ?: UserDraft.Regular("")
}
fun map(domain: UserDraft): DraftEntity {
return when (domain) {
is UserDraft.Regular -> DraftEntity(content = domain.content, draftMode = DraftEntity.MODE_REGULAR, linkedEventId = "")
- is UserDraft.Edit -> DraftEntity(content = domain.content, draftMode = DraftEntity.MODE_EDIT, linkedEventId = domain.linkedEventId)
- is UserDraft.Quote -> DraftEntity(content = domain.content, draftMode = DraftEntity.MODE_QUOTE, linkedEventId = domain.linkedEventId)
- is UserDraft.Reply -> DraftEntity(content = domain.content, draftMode = DraftEntity.MODE_REPLY, linkedEventId = domain.linkedEventId)
- is UserDraft.Voice -> DraftEntity(content = domain.content, draftMode = DraftEntity.MODE_VOICE, linkedEventId = "")
+ is UserDraft.Edit -> DraftEntity(content = domain.content, draftMode = DraftEntity.MODE_EDIT, linkedEventId = domain.linkedEventId)
+ is UserDraft.Quote -> DraftEntity(content = domain.content, draftMode = DraftEntity.MODE_QUOTE, linkedEventId = domain.linkedEventId)
+ is UserDraft.Reply -> DraftEntity(content = domain.content, draftMode = DraftEntity.MODE_REPLY, linkedEventId = domain.linkedEventId)
+ is UserDraft.Voice -> DraftEntity(content = domain.content, draftMode = DraftEntity.MODE_VOICE, linkedEventId = "")
}
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/EventMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/EventMapper.kt
index 5b60c53642..0f0a847c78 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/EventMapper.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/EventMapper.kt
@@ -130,7 +130,7 @@ internal fun EventEntity.asDomain(castJsonNumbers: Boolean = false): Event {
internal fun Event.toEntity(
roomId: String,
sendState: SendState,
- ageLocalTs: Long?,
+ ageLocalTs: Long,
contentToInject: String? = null
): EventEntity {
return EventMapper.map(this, roomId).apply {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/GroupSummaryMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/GroupSummaryMapper.kt
deleted file mode 100644
index 13c3a796c4..0000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/GroupSummaryMapper.kt
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.matrix.android.sdk.internal.database.mapper
-
-import org.matrix.android.sdk.api.session.group.model.GroupSummary
-import org.matrix.android.sdk.internal.database.model.GroupSummaryEntity
-
-internal object GroupSummaryMapper {
-
- fun map(groupSummaryEntity: GroupSummaryEntity): GroupSummary {
- return GroupSummary(
- groupSummaryEntity.groupId,
- groupSummaryEntity.membership,
- groupSummaryEntity.displayName,
- groupSummaryEntity.shortDescription,
- groupSummaryEntity.avatarUrl,
- groupSummaryEntity.roomIds.toList(),
- groupSummaryEntity.userIds.toList()
- )
- }
-}
-
-internal fun GroupSummaryEntity.asDomain(): GroupSummary {
- return GroupSummaryMapper.map(this)
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/HomeServerCapabilitiesMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/HomeServerCapabilitiesMapper.kt
index 20af43530c..184a0108b9 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/HomeServerCapabilitiesMapper.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/HomeServerCapabilitiesMapper.kt
@@ -42,7 +42,8 @@ internal object HomeServerCapabilitiesMapper {
lastVersionIdentityServerSupported = entity.lastVersionIdentityServerSupported,
defaultIdentityServerUrl = entity.defaultIdentityServerUrl,
roomVersions = mapRoomVersion(entity.roomVersionsJson),
- canUseThreading = entity.canUseThreading
+ canUseThreading = entity.canUseThreading,
+ canControlLogoutDevices = entity.canControlLogoutDevices
)
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/IsUselessResolver.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/IsUselessResolver.kt
index d704ecac8e..1a4821e80c 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/IsUselessResolver.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/IsUselessResolver.kt
@@ -32,7 +32,7 @@ internal object IsUselessResolver {
event.content != null &&
event.content.toContent() == event.resolvedPrevContent()?.toContent()
}
- else -> false
+ else -> false
}
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/LiveLocationShareAggregatedSummaryMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/LiveLocationShareAggregatedSummaryMapper.kt
index 9460e4c6ba..4a4c730a0b 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/LiveLocationShareAggregatedSummaryMapper.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/LiveLocationShareAggregatedSummaryMapper.kt
@@ -16,15 +16,17 @@
package org.matrix.android.sdk.internal.database.mapper
+import com.zhuinden.monarchy.Monarchy
import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.room.model.livelocation.LiveLocationShareAggregatedSummary
import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconLocationDataContent
import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntity
import javax.inject.Inject
-internal class LiveLocationShareAggregatedSummaryMapper @Inject constructor() {
+internal class LiveLocationShareAggregatedSummaryMapper @Inject constructor() :
+ Monarchy.Mapper {
- fun map(entity: LiveLocationShareAggregatedSummaryEntity): LiveLocationShareAggregatedSummary {
+ override fun map(entity: LiveLocationShareAggregatedSummaryEntity): LiveLocationShareAggregatedSummary {
return LiveLocationShareAggregatedSummary(
userId = entity.userId,
isActive = entity.isActive,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/RoomSummaryMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/RoomSummaryMapper.kt
index 9952a46f03..72b0f7a043 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/RoomSummaryMapper.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/RoomSummaryMapper.kt
@@ -106,12 +106,13 @@ internal class RoomSummaryMapper @Inject constructor(
worldReadable = it.childSummaryEntity?.joinRules == RoomJoinRules.PUBLIC
)
},
+ directParentNames = roomSummaryEntity.directParentNames.toList(),
flattenParentIds = roomSummaryEntity.flattenParentIds?.split("|") ?: emptyList(),
roomEncryptionAlgorithm = when (val alg = roomSummaryEntity.e2eAlgorithm) {
// I should probably use #hasEncryptorClassForAlgorithm but it says it supports
// OLM which is some legacy? Now only megolm allowed in rooms
MXCRYPTO_ALGORITHM_MEGOLM -> RoomEncryptionAlgorithm.Megolm
- else -> RoomEncryptionAlgorithm.UnsupportedAlgorithm(alg)
+ else -> RoomEncryptionAlgorithm.UnsupportedAlgorithm(alg)
}
)
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo010.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo010.kt
index aae80423ac..27423a9dca 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo010.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo010.kt
@@ -49,7 +49,7 @@ internal class MigrateSessionTo010(realm: DynamicRealm) : RealmMigrator(realm, 1
realm.schema.get("RoomSummaryEntity")
?.addField(RoomSummaryEntityFields.ROOM_TYPE, String::class.java)
?.addField(RoomSummaryEntityFields.FLATTEN_PARENT_IDS, String::class.java)
- ?.addField(RoomSummaryEntityFields.GROUP_IDS, String::class.java)
+ ?.addField("groupIds", String::class.java)
?.transform { obj ->
val creationEvent = realm.where("CurrentStateEventEntity")
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo029.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo029.kt
index aebca11c2b..17dc0f7c82 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo029.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo029.kt
@@ -25,7 +25,7 @@ import org.matrix.android.sdk.internal.util.database.RealmMigrator
* Migrating to:
* Live location sharing aggregated summary: adding new field userId.
*/
-internal class MigrateSessionTo029(realm: DynamicRealm) : RealmMigrator(realm, 28) {
+internal class MigrateSessionTo029(realm: DynamicRealm) : RealmMigrator(realm, 29) {
override fun doMigrate(realm: DynamicRealm) {
realm.schema.get("LiveLocationShareAggregatedSummaryEntity")
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo030.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo030.kt
new file mode 100644
index 0000000000..5d24b1433c
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo030.kt
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2022 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.internal.database.migration
+
+import io.realm.DynamicRealm
+import org.matrix.android.sdk.internal.database.model.ChunkEntityFields
+import org.matrix.android.sdk.internal.database.model.EventEntityFields
+import org.matrix.android.sdk.internal.database.model.TimelineEventEntityFields
+import org.matrix.android.sdk.internal.util.database.RealmMigrator
+import timber.log.Timber
+
+/**
+ * Migrating to:
+ * Cleaning old chunks which may have broken links.
+ */
+internal class MigrateSessionTo030(realm: DynamicRealm) : RealmMigrator(realm, 30) {
+
+ override fun doMigrate(realm: DynamicRealm) {
+ // Delete all previous chunks
+ val chunks = realm.where("ChunkEntity")
+ .equalTo(ChunkEntityFields.IS_LAST_FORWARD, false)
+ .findAll()
+
+ val nbOfDeletedChunks = chunks.size
+ var nbOfDeletedTimelineEvents = 0
+ var nbOfDeletedEvents = 0
+ chunks.forEach { chunk ->
+ val timelineEvents = chunk.getList(ChunkEntityFields.TIMELINE_EVENTS.`$`)
+ timelineEvents.forEach { timelineEvent ->
+ // Don't delete state events
+ val event = timelineEvent.getObject(TimelineEventEntityFields.ROOT.`$`)
+ if (event?.isNull(EventEntityFields.STATE_KEY) == true) {
+ nbOfDeletedEvents++
+ event.deleteFromRealm()
+ }
+ }
+ nbOfDeletedTimelineEvents += timelineEvents.size
+ timelineEvents.deleteAllFromRealm()
+ }
+ chunks.deleteAllFromRealm()
+ Timber.d(
+ "MigrateSessionTo030: $nbOfDeletedChunks deleted chunk(s)," +
+ " $nbOfDeletedTimelineEvents deleted TimelineEvent(s)" +
+ " and $nbOfDeletedEvents deleted Event(s)."
+ )
+ }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo031.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo031.kt
new file mode 100644
index 0000000000..e278b74756
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo031.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2022 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.internal.database.migration
+
+import io.realm.DynamicRealm
+import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEntityFields
+import org.matrix.android.sdk.internal.extensions.forceRefreshOfHomeServerCapabilities
+import org.matrix.android.sdk.internal.util.database.RealmMigrator
+
+internal class MigrateSessionTo031(realm: DynamicRealm) : RealmMigrator(realm, 31) {
+
+ override fun doMigrate(realm: DynamicRealm) {
+ realm.schema.get("HomeServerCapabilitiesEntity")
+ ?.addField(HomeServerCapabilitiesEntityFields.CAN_CONTROL_LOGOUT_DEVICES, Boolean::class.java)
+ ?.forceRefreshOfHomeServerCapabilities()
+ }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo032.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo032.kt
new file mode 100644
index 0000000000..1506b8c8b3
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo032.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2022 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.internal.database.migration
+
+import io.realm.DynamicRealm
+import org.matrix.android.sdk.internal.util.database.RealmMigrator
+
+internal class MigrateSessionTo032(realm: DynamicRealm) : RealmMigrator(realm, 32) {
+
+ override fun doMigrate(realm: DynamicRealm) {
+ realm.schema.get("RoomSummaryEntity")
+ ?.removeField("groupIds")
+ }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo033.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo033.kt
new file mode 100644
index 0000000000..0e3a8599c5
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo033.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.migration
+
+import io.realm.DynamicRealm
+import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntityFields
+import org.matrix.android.sdk.internal.util.database.RealmMigrator
+
+/**
+ * Migrating to:
+ * Live location sharing aggregated summary: adding new field relatedEventIds.
+ */
+internal class MigrateSessionTo033(realm: DynamicRealm) : RealmMigrator(realm, 33) {
+
+ override fun doMigrate(realm: DynamicRealm) {
+ realm.schema.get("LiveLocationShareAggregatedSummaryEntity")
+ ?.addRealmListField(LiveLocationShareAggregatedSummaryEntityFields.RELATED_EVENT_IDS.`$`, String::class.java)
+ }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo034.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo034.kt
new file mode 100644
index 0000000000..b23e84706f
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo034.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2022 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.internal.database.migration
+
+import io.realm.DynamicRealm
+import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntityFields
+import org.matrix.android.sdk.internal.util.database.RealmMigrator
+
+/**
+ * Migrating to:
+ * Live location sharing aggregated summary: adding new field startOfLiveTimestampMillis.
+ */
+internal class MigrateSessionTo034(realm: DynamicRealm) : RealmMigrator(realm, 34) {
+
+ override fun doMigrate(realm: DynamicRealm) {
+ realm.schema.get("LiveLocationShareAggregatedSummaryEntity")
+ ?.addField(LiveLocationShareAggregatedSummaryEntityFields.START_OF_LIVE_TIMESTAMP_MILLIS, Long::class.java)
+ ?.setNullable(LiveLocationShareAggregatedSummaryEntityFields.START_OF_LIVE_TIMESTAMP_MILLIS, true)
+ }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo035.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo035.kt
new file mode 100644
index 0000000000..5b3c95b4a2
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo035.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2022 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.internal.database.migration
+
+import io.realm.DynamicRealm
+import io.realm.RealmList
+import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields
+import org.matrix.android.sdk.internal.util.database.RealmMigrator
+
+internal class MigrateSessionTo035(realm: DynamicRealm) : RealmMigrator(realm, 35) {
+
+ override fun doMigrate(realm: DynamicRealm) {
+ realm.schema.get("RoomSummaryEntity")
+ ?.addRealmListField(RoomSummaryEntityFields.DIRECT_PARENT_NAMES.`$`, String::class.java)
+ ?.transform { it.setList(RoomSummaryEntityFields.DIRECT_PARENT_NAMES.`$`, RealmList("")) }
+ }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/GroupEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/GroupEntity.kt
deleted file mode 100644
index 0120bb91d3..0000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/GroupEntity.kt
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.matrix.android.sdk.internal.database.model
-
-import io.realm.RealmObject
-import io.realm.annotations.PrimaryKey
-import org.matrix.android.sdk.api.session.room.model.Membership
-
-/**
- * This class is used to store group info (groupId and membership) from the sync response.
- * Then GetGroupDataTask is called regularly to fetch group information from the homeserver.
- */
-internal open class GroupEntity(@PrimaryKey var groupId: String = "") :
- RealmObject() {
-
- private var membershipStr: String = Membership.NONE.name
- var membership: Membership
- get() {
- return Membership.valueOf(membershipStr)
- }
- set(value) {
- membershipStr = value.name
- }
-
- companion object
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/GroupSummaryEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/GroupSummaryEntity.kt
deleted file mode 100644
index d965148559..0000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/GroupSummaryEntity.kt
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.matrix.android.sdk.internal.database.model
-
-import io.realm.RealmList
-import io.realm.RealmObject
-import io.realm.annotations.PrimaryKey
-import org.matrix.android.sdk.api.session.room.model.Membership
-
-internal open class GroupSummaryEntity(
- @PrimaryKey var groupId: String = "",
- var displayName: String = "",
- var shortDescription: String = "",
- var avatarUrl: String = "",
- var roomIds: RealmList = RealmList(),
- var userIds: RealmList = RealmList()
-) : RealmObject() {
-
- private var membershipStr: String = Membership.NONE.name
- var membership: Membership
- get() {
- return Membership.valueOf(membershipStr)
- }
- set(value) {
- membershipStr = value.name
- }
-
- companion object
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/HomeServerCapabilitiesEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/HomeServerCapabilitiesEntity.kt
index 47a83f0ed9..9d90973f8a 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/HomeServerCapabilitiesEntity.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/HomeServerCapabilitiesEntity.kt
@@ -29,7 +29,8 @@ internal open class HomeServerCapabilitiesEntity(
var lastVersionIdentityServerSupported: Boolean = false,
var defaultIdentityServerUrl: String? = null,
var lastUpdatedTimestamp: Long = 0L,
- var canUseThreading: Boolean = false
+ var canUseThreading: Boolean = false,
+ var canControlLogoutDevices: Boolean = false
) : RealmObject() {
companion object
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/RoomSummaryEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/RoomSummaryEntity.kt
index cd755590be..471bec59af 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/RoomSummaryEntity.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/RoomSummaryEntity.kt
@@ -34,7 +34,8 @@ internal open class RoomSummaryEntity(
@PrimaryKey var roomId: String = "",
var roomType: String? = null,
var parents: RealmList = RealmList(),
- var children: RealmList = RealmList()
+ var children: RealmList = RealmList(),
+ var directParentNames: RealmList = RealmList(),
) : RealmObject() {
private var displayName: String? = ""
@@ -240,11 +241,6 @@ internal open class RoomSummaryEntity(
if (value != field) field = value
}
- var groupIds: String? = null
- set(value) {
- if (value != field) field = value
- }
-
@Index
private var membershipStr: String = Membership.NONE.name
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 890c2300f8..d131589dd1 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
@@ -32,8 +32,6 @@ import org.matrix.android.sdk.internal.database.model.threads.ThreadSummaryEntit
EventInsertEntity::class,
TimelineEventEntity::class,
FilterEntity::class,
- GroupEntity::class,
- GroupSummaryEntity::class,
ReadReceiptEntity::class,
RoomEntity::class,
RoomSummaryEntity::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
index c5df8e9338..ca793ffd8e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/livelocation/LiveLocationShareAggregatedSummaryEntity.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/livelocation/LiveLocationShareAggregatedSummaryEntity.kt
@@ -16,6 +16,7 @@
package org.matrix.android.sdk.internal.database.model.livelocation
+import io.realm.RealmList
import io.realm.RealmObject
import io.realm.annotations.PrimaryKey
@@ -29,6 +30,11 @@ internal open class LiveLocationShareAggregatedSummaryEntity(
@PrimaryKey
var eventId: String = "",
+ /**
+ * List of event ids used to compute the aggregated summary data.
+ */
+ var relatedEventIds: RealmList = RealmList(),
+
var roomId: String = "",
var userId: String = "",
@@ -38,6 +44,8 @@ internal open class LiveLocationShareAggregatedSummaryEntity(
*/
var isActive: Boolean? = null,
+ var startOfLiveTimestampMillis: Long? = null,
+
var endOfLiveTimestampMillis: Long? = null,
/**
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ChunkEntityQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ChunkEntityQueries.kt
index 9350102137..1e5d96b496 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ChunkEntityQueries.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ChunkEntityQueries.kt
@@ -31,6 +31,7 @@ internal fun ChunkEntity.Companion.where(realm: Realm, roomId: String): RealmQue
internal fun ChunkEntity.Companion.find(realm: Realm, roomId: String, prevToken: String? = null, nextToken: String? = null): ChunkEntity? {
val query = where(realm, roomId)
+ if (prevToken == null && nextToken == null) return null
if (prevToken != null) {
query.equalTo(ChunkEntityFields.PREV_TOKEN, prevToken)
}
@@ -40,7 +41,7 @@ internal fun ChunkEntity.Companion.find(realm: Realm, roomId: String, prevToken:
return query.findFirst()
}
-internal fun ChunkEntity.Companion.findAll(realm: Realm, roomId: String, prevToken: String? = null, nextToken: String? = null): RealmResults? {
+internal fun ChunkEntity.Companion.findAll(realm: Realm, roomId: String, prevToken: String? = null, nextToken: String? = null): RealmResults {
val query = where(realm, roomId)
if (prevToken != null) {
query.equalTo(ChunkEntityFields.PREV_TOKEN, prevToken)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/CurrentStateEventEntityQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/CurrentStateEventEntityQueries.kt
index e0dbf2eee8..e17d07c584 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/CurrentStateEventEntityQueries.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/CurrentStateEventEntityQueries.kt
@@ -23,13 +23,20 @@ import io.realm.kotlin.createObject
import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntity
import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntityFields
+internal fun CurrentStateEventEntity.Companion.whereRoomId(
+ realm: Realm,
+ roomId: String
+): RealmQuery {
+ return realm.where(CurrentStateEventEntity::class.java)
+ .equalTo(CurrentStateEventEntityFields.ROOM_ID, roomId)
+}
+
internal fun CurrentStateEventEntity.Companion.whereType(
realm: Realm,
roomId: String,
type: String
): RealmQuery {
- return realm.where(CurrentStateEventEntity::class.java)
- .equalTo(CurrentStateEventEntityFields.ROOM_ID, roomId)
+ return whereRoomId(realm = realm, roomId = roomId)
.equalTo(CurrentStateEventEntityFields.TYPE, type)
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/EventAnnotationsSummaryEntityQuery.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/EventAnnotationsSummaryEntityQuery.kt
index 6caa832110..1c19c21de2 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/EventAnnotationsSummaryEntityQuery.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/EventAnnotationsSummaryEntityQuery.kt
@@ -23,6 +23,11 @@ import org.matrix.android.sdk.internal.database.model.EventAnnotationsSummaryEnt
import org.matrix.android.sdk.internal.database.model.EventAnnotationsSummaryEntityFields
import org.matrix.android.sdk.internal.database.model.TimelineEventEntity
+internal fun EventAnnotationsSummaryEntity.Companion.where(realm: Realm, eventId: String): RealmQuery {
+ return realm.where()
+ .equalTo(EventAnnotationsSummaryEntityFields.EVENT_ID, eventId)
+}
+
internal fun EventAnnotationsSummaryEntity.Companion.where(realm: Realm, roomId: String, eventId: String): RealmQuery {
return realm.where()
.equalTo(EventAnnotationsSummaryEntityFields.ROOM_ID, roomId)
@@ -44,3 +49,7 @@ internal fun EventAnnotationsSummaryEntity.Companion.getOrCreate(realm: Realm, r
return EventAnnotationsSummaryEntity.where(realm, roomId, eventId).findFirst()
?: EventAnnotationsSummaryEntity.create(realm, roomId, eventId)
}
+
+internal fun EventAnnotationsSummaryEntity.Companion.get(realm: Realm, eventId: String): EventAnnotationsSummaryEntity? {
+ return EventAnnotationsSummaryEntity.where(realm, eventId).findFirst()
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/GroupEntityQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/GroupEntityQueries.kt
deleted file mode 100644
index 020592d1dd..0000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/GroupEntityQueries.kt
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.matrix.android.sdk.internal.database.query
-
-import io.realm.Realm
-import io.realm.RealmQuery
-import io.realm.kotlin.where
-import org.matrix.android.sdk.api.session.room.model.Membership
-import org.matrix.android.sdk.internal.database.model.GroupEntity
-import org.matrix.android.sdk.internal.database.model.GroupEntityFields
-import org.matrix.android.sdk.internal.query.process
-
-internal fun GroupEntity.Companion.where(realm: Realm, groupId: String): RealmQuery {
- return realm.where()
- .equalTo(GroupEntityFields.GROUP_ID, groupId)
-}
-
-internal fun GroupEntity.Companion.where(realm: Realm, memberships: List): RealmQuery {
- return realm.where().process(GroupEntityFields.MEMBERSHIP_STR, memberships)
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/GroupSummaryEntityQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/GroupSummaryEntityQueries.kt
deleted file mode 100644
index 8131598d95..0000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/GroupSummaryEntityQueries.kt
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.matrix.android.sdk.internal.database.query
-
-import io.realm.Realm
-import io.realm.RealmQuery
-import io.realm.kotlin.createObject
-import io.realm.kotlin.where
-import org.matrix.android.sdk.internal.database.model.GroupSummaryEntity
-import org.matrix.android.sdk.internal.database.model.GroupSummaryEntityFields
-
-internal fun GroupSummaryEntity.Companion.where(realm: Realm, groupId: String? = null): RealmQuery {
- val query = realm.where()
- if (groupId != null) {
- query.equalTo(GroupSummaryEntityFields.GROUP_ID, groupId)
- }
- return query
-}
-
-internal fun GroupSummaryEntity.Companion.where(realm: Realm, groupIds: List): RealmQuery