diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 34d7b40a88..501aa6784a 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -5,6 +5,6 @@
- [ ] Changes has been tested on an Android device or Android emulator with API 21
- [ ] UI change has been tested on both light and dark themes
- [ ] Pull request is based on the develop branch
-- [ ] Pull request updates [CHANGES.md](https://github.com/vector-im/element-android/blob/develop/CHANGES.md)
+- [ ] Pull request includes a new file under ./newsfragment. See https://github.com/vector-im/element-android/blob/develop/CONTRIBUTING.md#changelog
- [ ] Pull request includes screenshots or videos if containing UI changes
- [ ] Pull request includes a [sign off](https://github.com/matrix-org/synapse/blob/master/CONTRIBUTING.md#sign-off)
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 0000000000..85148a2632
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,59 @@
+name: APK Build
+
+on:
+ pull_request: { }
+ push:
+ branches: [ main, develop ]
+
+jobs:
+ debug:
+ name: Build debug APKs (${{ matrix.target }})
+ runs-on: ubuntu-latest
+ if: github.ref != 'refs/heads/main'
+ strategy:
+ fail-fast: false
+ matrix:
+ target: [ Gplay, Fdroid ]
+ steps:
+ - uses: actions/checkout@v2
+ - uses: actions/cache@v2
+ with:
+ path: |
+ ~/.gradle/caches
+ ~/.gradle/wrapper
+ key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
+ restore-keys: |
+ ${{ runner.os }}-gradle-
+ - name: Assemble ${{ matrix.target }} debug apk
+ run: ./gradlew assemble${{ matrix.target }}Debug --stacktrace
+ - name: Upload ${{ matrix.target }} debug APKs
+ uses: actions/upload-artifact@v2
+ with:
+ name: vector-${{ matrix.target }}-debug
+ path: |
+ vector/build/outputs/apk/*/debug/*.apk
+
+ release:
+ name: Build unsigned GPlay APKs
+ runs-on: ubuntu-latest
+ if: github.ref == 'refs/heads/main'
+ steps:
+ - uses: actions/checkout@v2
+ - uses: actions/cache@v2
+ with:
+ path: |
+ ~/.gradle/caches
+ ~/.gradle/wrapper
+ key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
+ restore-keys: |
+ ${{ runner.os }}-gradle-
+ - name: Assemble GPlay unsigned apk
+ run: ./gradlew clean assembleGplayRelease --stacktrace
+ - name: Upload Gplay unsigned APKs
+ uses: actions/upload-artifact@v2
+ with:
+ name: vector-gplay-release-unsigned
+ path: |
+ vector/build/outputs/apk/*/release/*.apk
+
+# TODO: add exodus checks
diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml
new file mode 100644
index 0000000000..cb6f1b0e48
--- /dev/null
+++ b/.github/workflows/integration.yml
@@ -0,0 +1,49 @@
+name: Integration Test
+
+on:
+ pull_request: { }
+ push:
+ branches: [ main, develop ]
+
+jobs:
+ integration-tests:
+ name: Integration Tests (Synapse)
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ api-level: [21, 30]
+ steps:
+ - uses: actions/checkout@v2
+ - name: Set up Python 3.8
+ uses: actions/setup-python@v2
+ with:
+ python-version: 3.8
+ - name: Cache pip
+ uses: actions/cache@v2
+ with:
+ path: ~/.cache/pip
+ key: ${{ runner.os }}-pip
+ restore-keys: |
+ ${{ runner.os }}-pip-
+ ${{ runner.os }}-
+ - uses: actions/cache@v2
+ with:
+ path: |
+ ~/.gradle/caches
+ ~/.gradle/wrapper
+ key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
+ restore-keys: |
+ ${{ runner.os }}-gradle-
+ - name: Start synapse server
+ run: |
+ python3 -m venv .synapse
+ source .synapse/bin/activate
+ pip install synapse matrix-synapse
+ curl -sL https://raw.githubusercontent.com/matrix-org/synapse/develop/demo/start.sh --no-rate-limit \
+ | sed s/127.0.0.1/0.0.0.0/g | bash
+ - name: Run integration tests on API ${{ matrix.api-level }}
+ uses: reactivecircus/android-emulator-runner@v2
+ with:
+ api-level: ${{ matrix.api-level }}
+ # script: ./gradlew -PallWarningsAsErrors=false vector:connectedAndroidTest matrix-sdk-android:connectedAndroidTest
+ script: ./gradlew -PallWarningsAsErrors=false connectedCheck
diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml
new file mode 100644
index 0000000000..a65e6b5dee
--- /dev/null
+++ b/.github/workflows/quality.yml
@@ -0,0 +1,74 @@
+name: Code Quality Checks
+
+on:
+ pull_request: { }
+ push:
+ branches: [ main, develop ]
+
+jobs:
+ check:
+ name: Project Check Suite
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - name: Run code quality check suite
+ run: ./tools/check/check_code_quality.sh
+
+ klint:
+ name: Kotlin Linter
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - name: Run klint
+ run: |
+ curl -sSLO https://github.com/pinterest/ktlint/releases/download/0.36.0/ktlint && chmod a+x ktlint
+ ./ktlint --android --experimental -v
+
+ android-lint:
+ name: Android Linter
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - uses: actions/cache@v2
+ with:
+ path: |
+ ~/.gradle/caches
+ ~/.gradle/wrapper
+ key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
+ restore-keys: |
+ ${{ runner.os }}-gradle-
+ - name: Lint analysis of the SDK
+ run: ./gradlew clean :matrix-sdk-android:lintRelease --stacktrace
+ - name: Upload reports
+ uses: actions/upload-artifact@v2
+ with:
+ name: linting-report-android-sdk
+ path: matrix-sdk-android/build/reports/*.*
+
+ 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 ]
+ steps:
+ - uses: actions/checkout@v2
+ - uses: actions/cache@v2
+ 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
+ uses: actions/upload-artifact@v2
+ if: always()
+ with:
+ name: release-debug-linting-report-${{ matrix.target }}
+ path: |
+ vector/build/reports/*.*
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
new file mode 100644
index 0000000000..6e51368ce5
--- /dev/null
+++ b/.github/workflows/tests.yml
@@ -0,0 +1,23 @@
+name: Test
+
+on:
+ pull_request: {}
+ push:
+ branches: [main, develop]
+
+jobs:
+ unit-tests:
+ name: Run Unit Tests
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - uses: actions/cache@v2
+ with:
+ path: |
+ ~/.gradle/caches
+ ~/.gradle/wrapper
+ key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
+ restore-keys: |
+ ${{ runner.os }}-gradle-
+ - name: Run unit tests
+ run: ./gradlew clean test --stacktrace -PallWarningsAsErrors=false
diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
index 89a7c466fd..523496e317 100644
--- a/.idea/codeStyles/Project.xml
+++ b/.idea/codeStyles/Project.xml
@@ -7,15 +7,6 @@
-
diff --git a/.idea/dictionaries/bmarty.xml b/.idea/dictionaries/bmarty.xml
index 4585842153..8299f1c4de 100644
--- a/.idea/dictionaries/bmarty.xml
+++ b/.idea/dictionaries/bmarty.xml
@@ -37,6 +37,7 @@
threepidunpublishunwedging
+ vctr
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
index 85bddac7f3..6e67639284 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,4 +1,4 @@
-# FTR: Configuration on https://travis-ci.org/vector-im/riotX-android/settings
+# 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
@@ -8,53 +8,11 @@
# - Auto cancel branch builds -> On
# - Auto cancel pull request builds -> On
-language: android
-jdk: oraclejdk8
sudo: false
notifications:
email: false
-android:
- components:
- # Uncomment the lines below if you want to
- # use the latest revision of Android SDK Tools
- - tools
- - platform-tools
-
- # The BuildTools version used by your project
- - build-tools-29.0.3
-
- # The SDK version used to compile your project
- - android-29
-
-before_cache:
- - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
- - rm -fr $HOME/.gradle/caches/*/plugin-resolution/
-
-cache:
- directories:
- - $HOME/.gradle/caches/
- - $HOME/.gradle/wrapper/
- - $HOME/.android/build-cache
-
-# Build with the development SDK
-before_script:
- # Not necessary for the moment
- # - /bin/sh ./set_debug_env.sh
-
-# Just build the project for now
+# Just run a simple script here
script:
- # Build app (assembleGplayRelease assembleFdroidRelease)
- # Build Android test (assembleAndroidTest) (disabled for now)
- # Code quality (lintGplayRelease lintFdroidRelease)
- # Split into two steps because if a task contain Fdroid, PlayService will be disabled
- # Done by Buildkite now: - ./gradlew clean assembleGplayRelease lintGplayRelease --stacktrace
- # Done by Buildkite now: - ./gradlew clean assembleFdroidRelease lintFdroidRelease --stacktrace
- # Run unitary test (Disable for now, see https://travis-ci.org/vector-im/riot-android/builds/502504370)
- # - ./gradlew testGplayReleaseUnitTest --stacktrace
- # Other code quality check
- # Done by Buildkite now: - ./tools/check/check_code_quality.sh
- ./tools/travis/check_pr.sh
- # Check that indonesians file are identical. Due to Android issue, the resource folder must be value-in/, and Weblate export data into value-id/.
- # Done by Buildkite now: - diff ./vector/src/main/res/values-id/strings.xml ./vector/src/main/res/values-in/strings.xml
diff --git a/CHANGES.md b/CHANGES.md
index 57582d884a..4dd4fd0cfd 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,29 +1,101 @@
-Changes in Element 1.1.7 (2021-XX-XX)
+Changes in Element v1.1.9 (2021-06-02)
+======================================
+
+Features ✨:
+ - Upgrade Olm dependency to 3.2.4
+ - Allow user to add custom "network" in room search (#1458)
+ - Add Gitter.im as a default in the Change Network menu (#3196)
+ - VoIP: support for virtual rooms (#3355)
+ - Compress thumbnail: change Jpeg quality from 100 to 80 (#3396)
+ - Inconsistent usage of the term homeserver in Settings (#3404)
+ - VoIP: support attended transfer (#3420)
+ - /snow -> /snowfall and update wording (iso Element Web) (#3430)
+
+Bugfixes 🐛:
+ - Fix | On Android it seems to be impossible to view the complete description of a Space (without dev tools) (#3401)
+ - Fix | Suggest Rooms, Show a detailed view of the room on click (#3406)
+ - Fix app crashing when signing out (#3424)
+ - Switch to stable endpoint/fields for MSC2858 (#3442)
+
+Changes in Element 1.1.8 (2021-05-25)
+===================================================
+
+Improvements 🙌:
+ - Support Jitsi authentication (#3379)
+
+Bugfix 🐛:
+ - Space Invite by link not always displayed for public space (#3345)
+ - Wrong copy in share space bottom sheet (#3346)
+ - Fix a problem with database migration on nightly builds (#3335)
+ - Implement a workaround to render <del> and <u> in the timeline (#1817)
+ - Make sure the SDK can retrieve the secret storage if the system is upgraded (#3304)
+ - Spaces | Explore room list: the RoomId is displayed instead of name (#3371)
+ - Spaces | Personal spaces add DM - Web Parity (#3271)
+ - Spaces | Improve 'Leave Space' UX/UI (#3359)
+ - Don't create private spaces with encryption enabled (#3363)
+ - #+ button on lower right when looking at an empty space goes to an empty 'Explore rooms' (#3327)
+
+Build 🧱:
+ - Compile with Kotlin 1.5.10.
+ - Upgrade some dependencies: gradle wrapper, third party lib, etc.
+ - Sign APK with build tools 30.0.3
+
+Other changes:
+ - Add documentation on LoginWizard and RegistrationWizard (#3303)
+ - Setup towncrier tool (#3293)
+
+ Security:
+ - Element Android shares name of E2EE files with homeserver (#3387)
+
+Changes in Element 1.1.7 (2021-05-12)
===================================================
Features ✨:
- -
+ - Spaces beta
Improvements 🙌:
- -
+ - Add ability to install APK from directly from Element (#2381)
+ - Delete and react to stickers (#3250)
+ - Compress video before sending (#442)
+ - Improve file too big error detection (#3245)
+ - User can now select video when selecting Gallery to send attachments to a room
+ - Add option to record a video from the camera
+ - Add the public icon on the rooms in the room list (#3292)
Bugfix 🐛:
- Message states cosmetic changes (#3007)
-
-Translations 🗣:
- -
+ - Fix exception in rxSingle (#3180)
+ - Do not invite the current user when creating a room (#3123)
+ - Fix color issues when the system theme is changed (#2738)
+ - Fix issues on Android 11 (#3067)
+ - Fix issue when opening encrypted files (#3186)
+ - Fix wording issue (#3242)
+ - Fix missing sender information after edits (#3184)
+ - Fix read marker not updating automatically (#3267)
+ - Sent video does not contains duration (#3272)
+ - Properly clean the back stack if the user cancel registration when waiting for email validation
+ - Fix read marker visibility/position when filtering some events
+ - Fix user invitation in case of restricted profile api (#3306)
SDK API changes ⚠️:
- -
+ - RegistrationWizard.createAccount() parameters are now all optional, following Matrix spec (#3205)
Build 🧱:
- Upgrade to gradle 7
-
-Test:
- -
+ - https://github.com/Piasy/BigImageViewer is now hosted on mavenCentral()
+ - Upgrade Realm to version 10.4.0
Other changes:
- New store descriptions
+ - `master` branch has been renamed to `main`. To apply change to your dev environment, run:
+```sh
+git branch -m master main
+git fetch origin
+git branch -u origin/main main
+# And optionally
+git remote prune origin
+```
+ - Allow cleartext (non-SSL) connections to Matrix servers on LAN hosts (#3166)
Changes in Element 1.1.6 (2021-04-16)
===================================================
@@ -44,7 +116,7 @@ Changes in Element 1.1.4 (2021-04-09)
Improvements 🙌:
- Split network request `/keys/query` into smaller requests (250 users max) (#2925)
- - Crypto improvement | Bulk send NO_OLM withheld code
+ - Crypto improvement | Bulk send NO_OLM withheld code
- Display the room shield in all room setting screens
- Improve message with Emoji only detection (#3017)
- Picture preview when replying. Also add the image preview in the message detail bottomsheet (#2916)
@@ -603,7 +675,7 @@ Improvements 🙌:
- Sending events is now retried only 3 times, so we avoid blocking the sending queue too long.
- Display warning when fail to send events in room list
- Improve UI of edit role action in member profile
- - Moderation | New screen to display list of banned users in room settings, with unban action
+ - Moderation | New screen to display list of banned users in room settings, with unban action
Bugfix 🐛:
- Fix theme issue on Room directory screen (#1613)
@@ -1323,36 +1395,3 @@ Changes in RiotX 0.1.0 (2019-07-11)
First release!
Mode details here: https://medium.com/@RiotChat/introducing-the-riotx-beta-for-android-b17952e8f771
-
-
-=======================================================
-+ TEMPLATE WHEN PREPARING A NEW RELEASE +
-=======================================================
-
-
-Changes in Element 1.1.X (2021-XX-XX)
-===================================================
-
-Features ✨:
- -
-
-Improvements 🙌:
- -
-
-Bugfix 🐛:
- -
-
-Translations 🗣:
- -
-
-SDK API changes ⚠️:
- -
-
-Build 🧱:
- -
-
-Test:
- -
-
-Other changes:
- -
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index dd32991051..7e1758077b 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -26,7 +26,7 @@ To install the template (to be done only once):
To create a new screen:
- First create a new package in your code.
-- Then right click on the package, and select `New/New Vector/RiotX Feature`.
+- Then right click on the package, and select `New/New Vector/Element Feature`.
- Follow the Wizard, especially replace `Main` by something more relevant to your feature.
- Click on `Finish`.
- Remaining steps are described as TODO in the generated files, or will be pointed out by the compiler, or at runtime :)
@@ -51,9 +51,21 @@ If an issue does not exist yet, it may be relevant to open a new issue and let u
This project is full Kotlin. Please do not write Java classes.
-### CHANGES.md
+### Changelog
-Please add a line to the top of the file `CHANGES.md` describing your change.
+Please create at least one file under ./newsfragment containing details about your change. Towncrier will be used when preparing the release.
+
+Towncrier says to use the PR number for the filename, but the issue number is also fine.
+
+Supported filename extensions are:
+
+- ``.feature``: Signifying a new feature in Element Android or in the Matrix SDK.
+- ``.bugfix``: Signifying a bug fix.
+- ``.doc``: Signifying a documentation improvement.
+- ``.removal``: Signifying a deprecation or removal of public API. Can be used to notifying about API change in the Matrix SDK
+- ``.misc``: A ticket has been closed, but it is not of interest to users. Note that in this case, the content of the file will not be output, but just the issue/PR number.
+
+See https://github.com/twisted/towncrier#news-fragments if you need more details.
### Code quality
diff --git a/attachment-viewer/build.gradle b/attachment-viewer/build.gradle
index 8db57a59af..c9814171d9 100644
--- a/attachment-viewer/build.gradle
+++ b/attachment-viewer/build.gradle
@@ -17,20 +17,6 @@
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
-buildscript {
- repositories {
- maven {
- url 'https://jitpack.io'
- content {
- // PhotoView
- includeGroupByRegex 'com\\.github\\.chrisbanes'
- }
- }
- jcenter()
- }
-
-}
-
android {
compileSdkVersion 30
@@ -61,15 +47,15 @@ android {
}
dependencies {
- implementation 'com.github.chrisbanes:PhotoView:2.1.4'
+ implementation 'com.github.chrisbanes:PhotoView:2.3.0'
implementation 'io.reactivex.rxjava2:rxkotlin:2.4.0'
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
- implementation 'androidx.core:core-ktx:1.3.2'
- implementation 'androidx.appcompat:appcompat:1.2.0'
- implementation "androidx.recyclerview:recyclerview:1.2.0"
+ implementation 'androidx.core:core-ktx:1.5.0'
+ implementation 'androidx.appcompat:appcompat:1.3.0'
+ implementation "androidx.recyclerview:recyclerview:1.2.1"
implementation 'com.google.android.material:material:1.3.0'
}
\ No newline at end of file
diff --git a/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AttachmentViewerActivity.kt b/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AttachmentViewerActivity.kt
index 418b5b5cbb..f909418d6f 100644
--- a/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AttachmentViewerActivity.kt
+++ b/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AttachmentViewerActivity.kt
@@ -33,6 +33,7 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.view.GestureDetectorCompat
import androidx.core.view.ViewCompat
+import androidx.core.view.WindowInsetsCompat
import androidx.core.view.isVisible
import androidx.core.view.updatePadding
import androidx.transition.TransitionManager
@@ -124,9 +125,11 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi
scaleDetector = createScaleGestureDetector()
ViewCompat.setOnApplyWindowInsetsListener(views.rootContainer) { _, insets ->
- overlayView?.updatePadding(top = insets.systemWindowInsetTop, bottom = insets.systemWindowInsetBottom)
- topInset = insets.systemWindowInsetTop
- bottomInset = insets.systemWindowInsetBottom
+ val systemBarsInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars())
+
+ overlayView?.updatePadding(top = systemBarsInsets.top, bottom = systemBarsInsets.bottom)
+ topInset = systemBarsInsets.top
+ bottomInset = systemBarsInsets.bottom
insets
}
}
diff --git a/build.gradle b/build.gradle
index 3268cfa084..b213066423 100644
--- a/build.gradle
+++ b/build.gradle
@@ -2,8 +2,8 @@
buildscript {
// Ref: https://kotlinlang.org/releases.html
- ext.kotlin_version = '1.4.32'
- ext.kotlin_coroutines_version = "1.4.2"
+ ext.kotlin_version = '1.5.10'
+ ext.kotlin_coroutines_version = "1.5.0"
repositories {
google()
jcenter()
@@ -12,11 +12,11 @@ buildscript {
}
}
dependencies {
- classpath 'com.android.tools.build:gradle:4.1.3'
- classpath 'com.google.gms:google-services:4.3.5'
+ classpath 'com.android.tools.build:gradle:4.2.1'
+ classpath 'com.google.gms:google-services:4.3.8'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
- classpath 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.1.1'
- classpath 'com.google.android.gms:oss-licenses-plugin:0.10.3'
+ classpath 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.3'
+ classpath 'com.google.android.gms:oss-licenses-plugin:0.10.4'
classpath "com.likethesalad.android:string-reference:1.2.2"
// NOTE: Do not place your application dependencies here; they belong
@@ -45,25 +45,20 @@ allprojects {
// PFLockScreen-Android
includeGroupByRegex 'com\\.github\\.vector-im'
- //Chat effects
+ // Chat effects
includeGroupByRegex 'com\\.github\\.jetradarmobile'
includeGroupByRegex 'nl\\.dionsegijn'
}
}
- maven {
- url "https://dl.bintray.com/piasy/maven"
- content {
- includeGroupByRegex "com\\.github\\.piasy"
- }
- }
maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
// Jitsi repo
maven {
- url "https://github.com/vector-im/jitsi_libre_maven/raw/master/android-sdk-3.1.0"
+ url "https://github.com/vector-im/jitsi_libre_maven/raw/main/android-sdk-3.1.0"
// Note: to test Jitsi release you can use a local file like this:
// url "file:///Users/bmarty/workspaces/jitsi_libre_maven/android-sdk-3.1.0"
}
google()
+ mavenCentral()
jcenter()
}
diff --git a/docs/color_migration_guide.md b/docs/color_migration_guide.md
new file mode 100644
index 0000000000..31a531d124
--- /dev/null
+++ b/docs/color_migration_guide.md
@@ -0,0 +1,85 @@
+# Color migration
+
+### Changes
+
+- use colors defined in https://www.figma.com/file/X4XTH9iS2KGJ2wFKDqkyed/Compound?node-id=557%3A0
+- remove unused resources and code (ex: PercentView)
+- split some resource files into smaller file
+- rework the theme files
+- ensure material theme is used everywhere in the theme and in the layout
+- add default style for some views in the theme (ex: Toolbar, etc.)
+- add some debug screen in the debug menu, to test the themes and the button style
+- rework the button style to use `materialThemeOverlay` attribute
+- custom tint icon for menu management has been removed
+- comment with `riotx` has been updated
+
+### Main change for developers
+
+- Read migration guide: https://github.com/vector-im/element-android/pull/3459/files#diff-f0e52729d5e4f6eccbcf72246807aa34ed19c4ef5625ca669df998cd1022874b
+- Use MaterialAlertDialogBuilder instead of AlertDialog.Builder
+- some Epoxy Item included a divider. This has been removed. Use a `dividerItem` or `bottomSheetDividerItem` Epoxy items to add a divider
+- RecyclerView.configureWith now take a divider drawable instead of a divider color
+
+### Remaining work
+
+- Cleanup some vector drawables and ensure a tint is always used instead of hard coded color.
+
+### Migration guide
+
+Some colors and color attribute has been removed, here is the list and what has to be used now.
+
+It can help Element Android forks maintainers to migrate their code.
+
+- riotx_text_primary -> ?vctr_content_primary
+- riotx_text_secondary -> ?vctr_content_secondary
+- riotx_text_tertiary -> ?vctr_content_tertiary
+
+- ?riotx_background -> ?android:colorBackground
+- riotx_background_light -> element_background_light
+- riotx_background_dark -> element_background_dark
+- riotx_background_black -> element_background_black
+
+- riotx_accent -> ?colorPrimary
+- riotx_positive_accent -> ?colorPrimary
+- riotx_accent_alpha25 -> color_primary_alpha25
+- riotx_notice -> ?colorError
+- riotx_destructive_accent -> ?colorError
+- vector_error_color -> ?colorError
+- vector_warning_color -> ?colorError
+
+- riotx_bottom_sheet_background -> ?colorSurface
+- riotx_alerter_background -> ?colorSurface
+
+- riotx_username_1 -> element_name_01
+- riotx_username_2 -> element_name_02
+- riotx_username_3 -> element_name_03
+- riotx_username_4 -> element_name_04
+- riotx_username_5 -> element_name_05
+- riotx_username_6 -> element_name_06
+- riotx_username_7 -> element_name_07
+- riotx_username_8 -> element_name_08
+
+- riotx_avatar_fill_1 -> element_room_01
+- riotx_avatar_fill_2 -> element_room_02
+- riotx_avatar_fill_3 -> element_room_03
+
+- white -> @android:color/white
+- black -> @android:color/black or emoji_color
+
+- riotx_list_header_background_color -> ?vctr_header_background
+- riotx_header_panel_background -> ?vctr_header_background
+- riotx_list_bottom_sheet_divider_color -> ?vctr_list_separator_on_surface
+- riotx_list_divider_color -> ?vctr_list_separator
+- list_divider_color -> ?vctr_list_separator
+- riotx_header_panel_border_mobile -> ?vctr_list_separator
+- riotx_bottom_nav_background_border_color -> ?vctr_list_separator
+- riotx_header_panel_text_secondary -> ?vctr_content_primary
+
+- link_color_light -> element_link_light
+- link_color_dark -> element_link_dark
+
+- riotx_toolbar_primary_text_color -> vctr_content_primary
+- riotx_toolbar_secondary_text_color -> vctr_content_primary
+- riot_primary_text_color -> vctr_content_primary
+
+- riotx_android_secondary -> vctr_content_secondary
diff --git a/fastlane/metadata/android/ca/changelogs/40101020.txt b/fastlane/metadata/android/ca/changelogs/40101020.txt
new file mode 100644
index 0000000000..43c140214f
--- /dev/null
+++ b/fastlane/metadata/android/ca/changelogs/40101020.txt
@@ -0,0 +1,2 @@
+Canvis principals d'aquesta versió: millora de rendiment i correcció d'errors!
+Registre de canvis complet: https://github.com/vector-im/element-android/releases/tag/v1.1.2
diff --git a/fastlane/metadata/android/ca/changelogs/40101030.txt b/fastlane/metadata/android/ca/changelogs/40101030.txt
new file mode 100644
index 0000000000..9b2627e7f2
--- /dev/null
+++ b/fastlane/metadata/android/ca/changelogs/40101030.txt
@@ -0,0 +1,2 @@
+Canvis principals d'aquesta versió: millora de rendiment i correcció d'errors!
+Registre de canvis complet: https://github.com/vector-im/element-android/releases/tag/v1.1.3
diff --git a/fastlane/metadata/android/cs/changelogs/40101020.txt b/fastlane/metadata/android/cs/changelogs/40101020.txt
new file mode 100644
index 0000000000..5e90e49daa
--- /dev/null
+++ b/fastlane/metadata/android/cs/changelogs/40101020.txt
@@ -0,0 +1,2 @@
+Hlavní změny v této verzi: vylepšení výkonnosti a opravy chyb!
+Úplný záznam změn: https://github.com/vector-im/element-android/releases/tag/v1.1.2
diff --git a/fastlane/metadata/android/cs/changelogs/40101030.txt b/fastlane/metadata/android/cs/changelogs/40101030.txt
new file mode 100644
index 0000000000..0e624ba6d1
--- /dev/null
+++ b/fastlane/metadata/android/cs/changelogs/40101030.txt
@@ -0,0 +1,2 @@
+Hlavní změny v této verzi: vylepšení výkonnosti a opravy chyb!
+Úplný záznam změn: https://github.com/vector-im/element-android/releases/tag/v1.1.3
diff --git a/fastlane/metadata/android/cs/changelogs/40101040.txt b/fastlane/metadata/android/cs/changelogs/40101040.txt
new file mode 100644
index 0000000000..1818c92ba8
--- /dev/null
+++ b/fastlane/metadata/android/cs/changelogs/40101040.txt
@@ -0,0 +1,2 @@
+Hlavní změny v této verzi: vylepšení výkonnosti a opravy chyb!
+Úplný záznam změn: https://github.com/vector-im/element-android/releases/tag/v1.1.4
diff --git a/fastlane/metadata/android/cs/changelogs/40101050.txt b/fastlane/metadata/android/cs/changelogs/40101050.txt
new file mode 100644
index 0000000000..3e33cd8d07
--- /dev/null
+++ b/fastlane/metadata/android/cs/changelogs/40101050.txt
@@ -0,0 +1,2 @@
+Hlavní změny v této verzi: nutné opravy pro 1.1.4
+Úplný záznam změn: https://github.com/vector-im/element-android/releases/tag/v1.1.5
diff --git a/fastlane/metadata/android/cs/changelogs/40101060.txt b/fastlane/metadata/android/cs/changelogs/40101060.txt
new file mode 100644
index 0000000000..d148a9bc37
--- /dev/null
+++ b/fastlane/metadata/android/cs/changelogs/40101060.txt
@@ -0,0 +1,2 @@
+Hlavní změny v této verzi: nutné opravy chyb pro 1.1.5!
+Úplný záznam změn: https://github.com/vector-im/element-android/releases/tag/v1.1.6
diff --git a/fastlane/metadata/android/cs/full_description.txt b/fastlane/metadata/android/cs/full_description.txt
index f9c1f2ad0c..d169c077e1 100644
--- a/fastlane/metadata/android/cs/full_description.txt
+++ b/fastlane/metadata/android/cs/full_description.txt
@@ -1,30 +1,39 @@
-Element je nový typ aplikace pro výměnu zpráv a spolupráci, která:
+Element je zabezpečený komunikátor a zároveň aplikace pro týmovou spolupráci, která je ideální pro skupinové chaty při práci na dálku. Tato chatovací aplikace využívá end-to-end šifrování a poskytuje výkonné videokonference, sdílení souborů a hlasové hovory.
-1. Vám dá kontrolu nad ochranou vašeho soukromí
-2. Umožní vám komunikovat s kýmkoli v síti Matrix a dokonce i mimo ni pomocí integrací s aplikacemi, jako je Slack
-3. Ochrání vás před inzercí, dataminingem a uzavřenými zahradami
-4. Zabezpečí vás end-to-end šifrováním s křížovým podpisem pro ověření ostatních
+Mezi funkce aplikace Element patří:
+- Pokročilé nástroje pro online komunikaci
+- Plně šifrované zprávy umožňující bezpečnější firemní komunikaci i pro pracovníky na dálku
+- Decentralizovaný chat založený na open source frameworku Matrix
+- Bezpečné sdílení souborů se šifrovanými daty při správě projektů
+- Videochaty s funkcí Voice over IP a sdílením obrazovky
+- Snadná integrace s oblíbenými nástroji pro online spolupráci, nástroji pro správu projektů, službami VoIP a dalšími aplikacemi pro týmovou komunikaci
-Element je zcela odlišný od ostatních aplikací pro zasílání zpráv a spolupráci, protože je decentralizovaný a otevřený.
+Element se zcela liší od ostatních aplikací pro zasílání zpráv a spolupráci. Funguje na platformě Matrix, otevřené síti pro bezpečné zasílání zpráv a decentralizovanou komunikaci. Umožňuje vlastní hostování, aby uživatelé měli maximální vlastnictví a kontrolu nad svými daty a zprávami.
-Element vám umožňuje použít vlastní domovský server - nebo si vybrat hostitele - abyste měli soukromí, vlastnictví a kontrolu nad svými daty a konverzacemi. Poskytuje vám přístup k otevřené síti; takže nejste zaseknuti jen při konverzaci s ostatními uživateli Elementu. A je velmi bezpečný.
+Soukromí a šifrované zprávy
+Element vás chrání před nežádoucími reklamami, vytěžováním dat a tzv. walled gardens. Zabezpečuje také všechna vaše data, video a hlasovou komunikaci jeden na jednoho prostřednictvím šifrování end-to-end a křížového ověřování zařízení.
-Element je toho všeho schopen, protože pracuje na Matrixu - standardu otevřené, decentralizované komunikace.
+Element vám dává kontrolu nad vaším soukromím a zároveň vám umožňuje bezpečně komunikovat s kýmkoli v síti Matrix nebo s dalšími nástroji pro firemní spolupráci díky integraci s aplikacemi, jako je Slack.
-Element vám dává kontrolu nad tím, že si můžete vybrat, kdo bude hostovat vaše konverzace. Z aplikace Element si můžete vybrat hostování různými způsoby:
+Element lze hostovat samostatně
+Abyste měli větší kontrolu nad svými citlivými daty a konverzacemi, může být Element hostován na vlastním hardwaru nebo si můžete vybrat libovolného hostitele založeného na systému Matrix - standardu pro decentralizovanou komunikaci s otevřeným zdrojovým kódem. Element vám poskytuje soukromí, soulad se zásadami bezpečnosti a flexibilitu integrace.
-1. Získejte zdarma účet na veřejném serveru matrix.org hostovaném vývojáři Matrixu, nebo si vyberte z tisíců veřejných serverů hostovaných dobrovolníky
-2. Hostujte svůj účet spuštěním serveru na svém vlastním hardwaru
-3. Zaregistrujte si účet na vlastním serveru jednoduchým přihlášením k hostitelské platformě Element Matrix Services
+Vlastněte svá data
+Sami rozhodujete, kde budou vaše data a zprávy uloženy. Bez rizika vytěžování dat nebo přístupu třetích stran.
-Proč zvolit Element?
+Element vám dává kontrolu různými způsoby:
+1. Získejte bezplatný účet na veřejném serveru matrix.org, který hostují vývojáři Matrixu, nebo si vyberte z tisíců veřejných serverů hostovaných dobrovolníky.
+2. Vlastní hostování účtu spuštěním serveru na vlastní IT infrastruktuře.
+3. Zaregistrujte si účet na vlastním serveru tak, že si jednoduše předplatíte hostingovou platformu Element Matrix Services.
-VLASTNĚTE SVÁ DATA: Vy rozhodnete, kde svá data a zprávy ponecháte. Vlastníte je a jsou pod vaší kontrolou, ne nějaký MEGACORP, který těží vaše data nebo poskytuje přístup třetím stranám.
+Otevřené zasílání zpráv a spolupráce
+Můžete chatovat s kýmkoli v síti Matrix, ať už používá aplikaci Element, jinou aplikaci podporující protokol Matrix nebo dokonce i když používá jinou aplikaci pro zasílání zpráv.
-ZPRÁVY A SPOLUPRÁCE: Můžete chatovat s kýmkoli v síti Matrix, ať už používá Element nebo jinou aplikaci, a to i v případě, že používají jiný systém zasílání zpráv, jako je Slack, IRC nebo XMPP.
+Superbezpečné
+Skutečné end-to-end šifrování (zprávy mohou dešifrovat pouze účastníci konverzace) a křížové ověřování zařízení.
-MAXIMÁLNĚ BEZPEČNÉ: Skutečné šifrování typu end-to-end (pouze ti v konverzaci mohou dešifrovat zprávy) a křížové podepisování k ověření zařízení účastníků konverzace.
+Kompletní komunikace a integrace
+Zprávy, hlasové a videohovory, sdílení souborů, sdílení obrazovky a celá řada integrací, botů a widgetů. Vytvářejte místnosti, komunity, zůstaňte v kontaktu a spolupracujte.
-KOMPLETNÍ KOMUNIKACE: Zprávy, hlasové hovory a videohovory, sdílení souborů, sdílení obrazovky a celá řada integrací, robotů a widgetů. Budujte místnosti, komunity, zůstaňte v kontaktu a spolupracujte.
-
-KDEKOLIV JSTE: Zůstaňte v kontaktu, ať jste kdekoli, s plně synchronizovanou historií zpráv na všech vašich zařízeních a na webu na adrese https://app.element.io.
+Navažte tam, kde jste skončili
+Zůstaňte v kontaktu, ať jste kdekoli, díky plně synchronizované historii zpráv ve všech zařízeních a na webu https://app.element.io
diff --git a/fastlane/metadata/android/cs/short_description.txt b/fastlane/metadata/android/cs/short_description.txt
index a654a9ea6a..d14ac49efa 100644
--- a/fastlane/metadata/android/cs/short_description.txt
+++ b/fastlane/metadata/android/cs/short_description.txt
@@ -1 +1 @@
-Zabezpečený decentralizovaný chat a VoIP. Uchovejte svá data v bezpečí.
+Skupinový messenger - šifrovaná komunikace, skupinový chat a video hovory
diff --git a/fastlane/metadata/android/cs/title.txt b/fastlane/metadata/android/cs/title.txt
index 76943289ad..2fedfecb15 100644
--- a/fastlane/metadata/android/cs/title.txt
+++ b/fastlane/metadata/android/cs/title.txt
@@ -1 +1 @@
-Element (dříve Riot.im)
+Element - bezpečný messenger
diff --git a/fastlane/metadata/android/de/changelogs/40100110.txt b/fastlane/metadata/android/de/changelogs/40100110.txt
index 24bc6e518c..120f04a3f9 100644
--- a/fastlane/metadata/android/de/changelogs/40100110.txt
+++ b/fastlane/metadata/android/de/changelogs/40100110.txt
@@ -1,2 +1,2 @@
-Diese neue Version enthält hauptsächlich Verbesserungen der Benutzeroberfläche und der Handhabung. Du kannst jetzt ganz schnell Freund*innen einladen und DMs erstellen, indem du schlicht einen QR-Code scannst.
+Diese neue Version enthält hauptsächlich Verbesserungen der Benutzeroberfläche und der Handhabung. Du kannst jetzt ganz schnell Freunde einladen und DMs erstellen, indem du schlicht einen QR-Code scannst.
Vollständige Versionshinweise: https://github.com/vector-im/element-android/releases/tag/v1.0.11
diff --git a/fastlane/metadata/android/de/changelogs/40101020.txt b/fastlane/metadata/android/de/changelogs/40101020.txt
new file mode 100644
index 0000000000..32fabf7c2f
--- /dev/null
+++ b/fastlane/metadata/android/de/changelogs/40101020.txt
@@ -0,0 +1,2 @@
+Hauptänderungen in dieser Version: Leistungsverbesserung und Fehlerbehebungen!
+Vollständiges Änderungsprotokoll: https://github.com/vector-im/element-android/releases/tag/v1.1.2
diff --git a/fastlane/metadata/android/de/changelogs/40101030.txt b/fastlane/metadata/android/de/changelogs/40101030.txt
new file mode 100644
index 0000000000..7e6dc25033
--- /dev/null
+++ b/fastlane/metadata/android/de/changelogs/40101030.txt
@@ -0,0 +1,2 @@
+Hauptänderungen in dieser Version: Leistungsverbesserung und Fehlerbehebungen!
+Vollständiges Änderungsprotokoll: https://github.com/vector-im/element-android/releases/tag/v1.1.3
diff --git a/fastlane/metadata/android/de/changelogs/40101040.txt b/fastlane/metadata/android/de/changelogs/40101040.txt
new file mode 100644
index 0000000000..eaa8db1409
--- /dev/null
+++ b/fastlane/metadata/android/de/changelogs/40101040.txt
@@ -0,0 +1,2 @@
+Hauptänderungen in dieser Version: Leistungsverbesserung und Fehlerbehebungen!
+Vollständiges Änderungsprotokoll: https://github.com/vector-im/element-android/releases/tag/v1.1.4
diff --git a/fastlane/metadata/android/de/changelogs/40101050.txt b/fastlane/metadata/android/de/changelogs/40101050.txt
new file mode 100644
index 0000000000..de6352961a
--- /dev/null
+++ b/fastlane/metadata/android/de/changelogs/40101050.txt
@@ -0,0 +1,2 @@
+Hauptänderungen in dieser Version: Wichtige Fehlerbehebungen für 1.1.4!
+Vollständiges Änderungsprotokoll: https://github.com/vector-im/element-android/releases/tag/v1.1.5
diff --git a/fastlane/metadata/android/de/changelogs/40101060.txt b/fastlane/metadata/android/de/changelogs/40101060.txt
new file mode 100644
index 0000000000..775c016b3d
--- /dev/null
+++ b/fastlane/metadata/android/de/changelogs/40101060.txt
@@ -0,0 +1,2 @@
+Hauptänderungen in dieser Version: Wichtige Fehlerbehebungen für 1.1.5!
+Vollständiges Änderungsprotokoll: https://github.com/vector-im/element-android/releases/tag/v1.1.6
diff --git a/fastlane/metadata/android/de/changelogs/40101070.txt b/fastlane/metadata/android/de/changelogs/40101070.txt
new file mode 100644
index 0000000000..757475a44d
--- /dev/null
+++ b/fastlane/metadata/android/de/changelogs/40101070.txt
@@ -0,0 +1,2 @@
+Hauptänderungen in dieser Version: Mit Spaces kannst du deine Räume gruppieren (Beta). Videos können vor dem Senden komprimiert werden.
+Die vollständige Änderungsliste gibt es hier: https://github.com/vector-im/element-android/releases/tag/v1.1.7
diff --git a/fastlane/metadata/android/de/full_description.txt b/fastlane/metadata/android/de/full_description.txt
index 568ae61875..30eb153ee9 100644
--- a/fastlane/metadata/android/de/full_description.txt
+++ b/fastlane/metadata/android/de/full_description.txt
@@ -1,30 +1,39 @@
-Element ist eine neuartige Messaging- und Kollaborationsapp:
+Element ist ein sicherer Messenger und ideal für die produktive Zusammenarbeit mit Ihrem Team im Homeoffice. Mit eingebauter Ende-zu-Ende-Verschlüsselung ermöglicht Element auch umfangreiche und sichere Videokonferenzen, das Teilen von Dateien, Sprachanrufe und vieles mehr.
-1. Volle Kontrolle über deine Privatssphäre
-2. Kommuniziere mit jedem aus dem Matrix-Netzwerk und mit der Integration von z.B. Slack sogar über Matrix hinaus
-3. Schutz vor Werbung, Datamining und geschlossenen Platformen
-4. Absicherung durch Ende-zu-Ende-Verschlüsselung, und Cross-Signing um andere zu verifizieren
+Element bietet folgende Funktionen:
+- Fortschrittliche Werkzeuge für die Online-Kommunikation
+- Vollständig verschlüsselte Nachrichten, um eine sichere Kommunikation innerhalb und außerhalb von Unternehmen zu ermöglichen
+- Dezentralisierte Chats, basierend auf dem quelloffenen Matrix-Protokoll
+- Sichere und kontrollierte Dateifreigabe durch verschlüsselte Daten beim Verwalten von Projekten
+- Videochats mit VoIP und Bildschirmübertragung
+- Einfache Einbindung in Ihre bevorzugten Online-Kollaborations- und Projektverwaltungswerkzeuge, VoIP-Dienste und andere Kommunikationsapps für Ihr Team
-Element unterscheidet sich durch Dezentralität und Open Source deutlich von anderen Messaging- und Kollaborationsapps.
+Element unterscheidet sich grundlegend von anderen Kommunikations- und Kollaborationsapps. Es läuft auf Matrix, einem offenen Netzwerk für sichere und dezentralisierte Kommunikation. Es erlaubt Nutzern ihre eigene Infrastruktur zu betreiben und gibt ihnen damit vollständige Kontrolle und Besitz über ihre eigenen Daten und Nachrichten.
-Element ermöglicht es einen eigenen Server zu betreiben - oder einen beliebigen auszuwählen, sodass du nicht nur Privatssphäre gewinnst, sondern auch deine Daten und Konversationen in deiner Hand sind und du sie kontrollieren kannst. Du hast Zugriff auf ein offenes Netzwerk, und kannst daher nicht nur mit Element-Nutzern schreiben. Und es ist sehr sicher.
+Privatsphäre/Datenschutz und verschlüsselte Kommunikation
+Element schützt Sie vor unerwünschter Werbung, dem Datensammeln und geschlossenen Plattformen. Auch schützt es all Ihre Daten, Ihre Video- und Sprachkommunikation mittels Ende-zu-Ende-Verschlüsselung und durch das Quersignieren von Geräten zur Verifizierung.
-Element ist zu all diesem in der Lage, weil es Matrix nutzt - einen Standard für offene, dezentrale Kommunikation.
+Element gibt Ihnen volle Kontrolle über Ihre Privatsphäre und ermöglicht es Ihnen zugleich, mit jedem im Matrix-Netzwerk sicher zu kommunizieren - oder auch auf anderen geschäftlichen Kollaborationswerkzeugen, zum Beispiel durch das Einbinden von Apps wie Slack.
-Element gibt dir die Kontrolle, indem es dir die Wahl darüber lässt, wer deine Konversationen hostet. In der Element-App kannst du zwischen verschiedenen Möglichkeiten auswählen:
+Element kann man selber betreiben
+Um mehr Kontrolle über Ihre sensiblen Daten und Konversationen zu ermöglichen, kann man Element selbst betreiben, oder Sie wählen irgendeinen Matrix-basierten Dienst - der Standard für quelloffene, dezentralisierte Kommunikation. Element gibt Ihnen Privatsphäre, Sicherheitskonformität und Flexibilität für Integrationen.
-1. Kostenlos auf dem öffentlichen matrix.org Server registrieren, der von den Matrix-Entwicklern gehostet wird, oder wähle aus Tausenden von öffentlichen Servern, die von Freiwilligen gehostet werden
-2. Einen Konto auf einem eigenen Server auf eigener Hardware betreiben
-3. Einen Konto auf einem benutzerdefinierten Server erstellen, zum Beispiel durch ein Abonnement bei Element Matrix Services (kurz EMS)
+Besitzen Sie Ihre Daten
+Sie entscheiden, wo Sie Ihre Daten und Nachrichten aufbewahren - ohne das Datensammeln oder den Zugriff Dritter zu riskieren.
-Wieso Element nutzen?
+Element gibt Ihnen auf verschiedene Arten Kontrolle:
+1. Sie können sich kostenlos auf dem öffentlichen matrix.org-Server registrieren, der von den Matrix-Entwicklern gehostet wird, oder einen von Tausenden öffentlichen Servern, die von Freiwilligen betrieben werden, auswählen
+2. Sie haben die Möglichkeit, ein Konto auf einem eigenen Server in der eigenen IT-Infrastruktur betreiben
+3. Außerdem können Sie durch ein Abonnement der Element Matrix Services ein Konto auf einem für Sie maßgeschneiderten Server erstellen
-BESITZE DEINE DATEN: Du entscheidest wo deine Daten und Nachrichten gespeichert werden. Du besitzt und kontrollierst sie, anstatt ein Großkonzern, der deine Daten analysiert und Dritten Zugriff gibt.
+Offene Kommunikation und Zusammenarbeit
+Sie können mit jedem im Matrix-Netzwerk chatten, egal ob ihr Kontakt Element, eine andere Matrix-App oder sogar eine völlig andere Anwendung nutzt.
-OFFENE KOMMUNIKATION UND KOLLABORATION: Du kannst mit jedem im Matrix-Netzwerk schreiben, ob sie nun Element oder eine andere Matrix-App nutzen, oder gar ein anderes Kommunikationssystem wie z.B. Slack, IRC oder XMPP.
+Super sicher
+Durch Ende-zu-Ende-Verschlüsselung können nur die Personen, die in der Unterhaltung sind, die Nachrichten lesen. Außerdem stellt die Verifizierung mittels Quersignierung sicher, dass Sie wirklich mit dem Chatten, mit dem Sie glauben - und niemand Anderem.
-SUPER SICHER: Echte Ende-zu-Ende-Verschlüsselung (nur Personen in der Konversation können die Nachrichten entschlüsseln), und Cross-Signing um die Geräte der anderen Personen zu verifizieren.
+Vollständige Kommunikation und Integration
+Kurznachrichten, Sprach- und Videoanrufe, Dateifreigaben, Bildschirmübertragungen und einer Menge an Integrationen, Bots und Widgets. Schaffen Sie Räume und Communities, bleiben Sie auf dem Laufenden und erledigen Sie Sachen.
-VOLLSTÄNDIGE KOMMUNIKATION: Nachrichten, Telefonate und Videoanrufe, Teilen von Dateien oder dem eigenen Bildschirm und viele andere Integrationen, Bots und Widgets. Erstelle Räume, Communities, bleib in Kontakt und sei produktiv.
-
-ÜBERALL WO DU BIST: Bleib in Kontakt wo auch immer du bist - mit einem vollständig synchronisierten Nachrichtenverlauf über alle Geräte und im Netz auf https://app.element.io.
+Da Weitermachen, wo Sie aufgehört haben
+Bleiben Sie in Kontakt, egal wo Sie sind, mit vollständig synchronisiertem Nachrichtenverlauf quer über all Ihre Geräte und im Netz auf https://app.element.io
diff --git a/fastlane/metadata/android/de/short_description.txt b/fastlane/metadata/android/de/short_description.txt
index d2c30d4167..d27bd3ef12 100644
--- a/fastlane/metadata/android/de/short_description.txt
+++ b/fastlane/metadata/android/de/short_description.txt
@@ -1 +1 @@
-Sicherer dezentraler Chat und Telefonie. Schütze deine Daten vor Dritten.
+Gruppen-Messenger - verschlüsselte Kommunikation, Gruppenchat und Videoanrufe
diff --git a/fastlane/metadata/android/de/title.txt b/fastlane/metadata/android/de/title.txt
index ec25e8a631..6304f37925 100644
--- a/fastlane/metadata/android/de/title.txt
+++ b/fastlane/metadata/android/de/title.txt
@@ -1 +1 @@
-Element (zuvor Riot.im)
+Element - Sicherer Messenger
diff --git a/fastlane/metadata/android/en-US/changelogs/40101070.txt b/fastlane/metadata/android/en-US/changelogs/40101070.txt
new file mode 100644
index 0000000000..254e4c0f62
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/40101070.txt
@@ -0,0 +1,2 @@
+Main changes in this version: beta support for Spaces. Compress video before sending.
+Full changelog: https://github.com/vector-im/element-android/releases/tag/v1.1.7
\ No newline at end of file
diff --git a/fastlane/metadata/android/en-US/changelogs/40101080.txt b/fastlane/metadata/android/en-US/changelogs/40101080.txt
new file mode 100644
index 0000000000..f94a332ec3
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/40101080.txt
@@ -0,0 +1,2 @@
+Main changes in this version: improvement for Spaces.
+Full changelog: https://github.com/vector-im/element-android/releases/tag/v1.1.8
\ No newline at end of file
diff --git a/fastlane/metadata/android/en-US/changelogs/40101090.txt b/fastlane/metadata/android/en-US/changelogs/40101090.txt
new file mode 100644
index 0000000000..a5a4e14a29
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/40101090.txt
@@ -0,0 +1,2 @@
+Main changes in this version: add support for gitter.im network.
+Full changelog: https://github.com/vector-im/element-android/releases/tag/v1.1.9
\ No newline at end of file
diff --git a/fastlane/metadata/android/et/changelogs/40101020.txt b/fastlane/metadata/android/et/changelogs/40101020.txt
new file mode 100644
index 0000000000..5f34bb579f
--- /dev/null
+++ b/fastlane/metadata/android/et/changelogs/40101020.txt
@@ -0,0 +1,2 @@
+Põhilised muutused selles versioonis: jõudluse parandused ja pisikohendused.
+Kogu ingliskeelne muudatuste logi: https://github.com/vector-im/element-android/releases/tag/v1.1.2
diff --git a/fastlane/metadata/android/et/changelogs/40101030.txt b/fastlane/metadata/android/et/changelogs/40101030.txt
new file mode 100644
index 0000000000..5a558d911a
--- /dev/null
+++ b/fastlane/metadata/android/et/changelogs/40101030.txt
@@ -0,0 +1,2 @@
+Põhilised muutused selles versioonis: jõudluse parandused ja pisikohendused.
+Kogu ingliskeelne muudatuste logi: https://github.com/vector-im/element-android/releases/tag/v1.1.3
diff --git a/fastlane/metadata/android/et/changelogs/40101040.txt b/fastlane/metadata/android/et/changelogs/40101040.txt
new file mode 100644
index 0000000000..2e7849db9e
--- /dev/null
+++ b/fastlane/metadata/android/et/changelogs/40101040.txt
@@ -0,0 +1,2 @@
+Põhilised muutused selles versioonis: jõudluse parandused ja pisikohendused.
+Kogu ingliskeelne muudatuste logi: https://github.com/vector-im/element-android/releases/tag/v1.1.5
diff --git a/fastlane/metadata/android/et/changelogs/40101050.txt b/fastlane/metadata/android/et/changelogs/40101050.txt
new file mode 100644
index 0000000000..9aa2f4e10c
--- /dev/null
+++ b/fastlane/metadata/android/et/changelogs/40101050.txt
@@ -0,0 +1,2 @@
+Põhilised muutused selles versioonis: kiirparandused versioon 1.1.4 jaoks.
+Kogu ingliskeelne muudatuste logi: https://github.com/vector-im/element-android/releases/tag/v1.1.5
diff --git a/fastlane/metadata/android/et/changelogs/40101060.txt b/fastlane/metadata/android/et/changelogs/40101060.txt
new file mode 100644
index 0000000000..0577bf452d
--- /dev/null
+++ b/fastlane/metadata/android/et/changelogs/40101060.txt
@@ -0,0 +1,2 @@
+Põhilised muutused selles versioonis: kiirparandused versioon 1.1.5 jaoks.
+Kogu ingliskeelne muudatuste logi: https://github.com/vector-im/element-android/releases/tag/v1.1.6
diff --git a/fastlane/metadata/android/et/changelogs/40101070.txt b/fastlane/metadata/android/et/changelogs/40101070.txt
new file mode 100644
index 0000000000..8ef65a7396
--- /dev/null
+++ b/fastlane/metadata/android/et/changelogs/40101070.txt
@@ -0,0 +1,2 @@
+Põhilised muudatused selles versioonis: beeta-versioon kogukonnakeskustest ja videofailide pakkimine enne üleslaadimist.
+Kogu ingliskeelne muudatuste logi: https://github.com/vector-im/element-android/releases/tag/v1.1.7
diff --git a/fastlane/metadata/android/et/full_description.txt b/fastlane/metadata/android/et/full_description.txt
index 7c7f7195a8..ee0adef9ac 100644
--- a/fastlane/metadata/android/et/full_description.txt
+++ b/fastlane/metadata/android/et/full_description.txt
@@ -1,30 +1,39 @@
-Element on uut tüüpi suhtlus- ja koostöörakendus, mis:
+Element on nii suhtlus- ja koostöörakendus, mis sobib ideaalselt rühmavestlusteks kaugtöö ajal. Läbiv krüptimine on kasutusel sõnumivahetuseks, videokõnedeks, häälkõnedeks ja failide jagamiseks.
-1. Võimaldab täielikku kontrolli privaatsuse üle
-2. Võimaldab suhelda kõigiga Matrixi võrgus ja isegi väljaspool seda, olles integreeritud selliste rakendustega nagu Slack
-3. Kaitseb sind reklaamide ja andmekogumise eest
-4. Tagab turvalisuse läbiva krüptimise abil, kasutades risttunnustamist vestlejate tuvastamiseks
+Element pakub muu hulgas selliseid võimalusi
+- moodsad võrgupõhised suhtlusvahendid
+- läbivalt krüptitud sõnumid võimaldavad turvalist suhtlust, sealhulgas kaugtöötajatega
+- Matrix'i protokollil põhinev hajutatud suhtlusvõrk
+- projektide jaoks vajalike failide jagamine turvaliselt ja krüptitult
+- VoIP'i põhised videokõned ja ekraani jagamine
+- lihtne lõimimine harjumispäraste võrgupõhiste koostöövahenditega, projektihalduse rakendustega, VoIP-teenustega ja muude ühistöörakendustega
-Element erineb täielikult teistest sõnumside- ja koostöörakendustest, kuna see on detsentraliseeritud ja avatud lähtekoodiga.
+Element erineb teistest sõnumi- ja koostöörakendustest. Tema aluseks on Matrix - avatud võrk turvalise ja hajutatud suhtluse jaoks.
-Element võimaldab ise hostida - või valida hosti -, et oleks tagatud privaatsus ja kontroll oma andmete ja vestluste üle. Element annab ka juurdepääsu avatud võrgule, nii et te ei pea vaid Elemendi kasutajatega rääkima. Ning kogu süsteem on väga turvaline.
+Privaatsus ja krüptitud sõnumivahetus
+Element tagab, et sa ei ole seotud reklaamidega, andmekogumisega ja suletud süsteemidega. Kasutades läbivat krüptimist ja risttunnustamisel põhinevat verifitseerimist on sinu sõnumid, andmed, kahepoolsed videokõned ja häälkõned turvatud.
-Element töötab Matrixil - avatud, detsentraliseeritud suhtlus-standardil.
+Lubades suhelda turvaliselt ükspuha kellega Matrix'i võrgus või muude ärikeskondades kasutatavate koostöörakendustega nagu Slack, jätab Element sulle kontrolli oma privaatsuse üle.
-Võimaldades valida, kes vestlusi korraldab, annab Element annab kontrolli sinule. Rakendust Element saad kasutada mitmel viisil.
+Võid kasutada Element'i jaoks oma serverid
+Kui vajad suuremat kontrolli oma suhtluse ja andmete üle, siis võid kasutada oma serverit või tellida teenuse ükspuha missuguselt Matrix'i-teenuse pakkujalt. Matrix on standard avatud lähtekoodil põhineva detsentraliseeritud suhtluse jaoks.
-1. Tasuta konto Matrixi arendajate hostitud avalikus serveris matrix.org või vali tuhandete avalike serverite hulgast, mida haldavad vabatahtlikud
-2. Hosti oma kontot ise, paigaldades serveri oma riistvarale
-3. Registreeruge serveris olevale kontole, tellides Element Matrix Services teenuseplatvormi
+Andmed on Sinu omad
+Sina otsustad seda, kus hoiad oma sõnumeid ja andmeid. Ning seejuures puudub andmekaevandamise risk ja ligipääs kolmandatele osapooltele.
- Miks valida element?
+Element annab kontrolli sinule valikuga mitme võimaluse vahel:
+1. tasuta konto Matrix'i arendajate hostitud avalikus serveris matrix.org või vali tuhandete avalike serverite hulgast, mida haldavad vabatahtlikud
+2. hosti oma kontot ise, paigaldades serveri oma IT-taristule
+3. telli tasuline kasutajakonto Element Matrix Services teenuseplatvormilt
- KONTROLL ANDMETE ÜLE: otsustad ise, kus oma andmeid ja sõnumeid hoida. Need kuuluvad sulle ja sinu käes on kontroll, mitte mõne MEGAFIRMA käes, mis andmeid oma kasuks kaevandab või kolmandatele isikutele juurdepääsu annab.
+Avatud suhtlus ja koostöö
+Saad vestelda kõigi teistega Matrix'i võrgus, olenemata sellest, kas nad kasutavad Elementi või mõnda muud Matrixi rakendust ja isegi kui nad kasutavad mõnda teistsugust suhtlussüsteemi.
- AVATUD SUHTLUS JA KOOSTÖÖ : saad vestelda kõigi teistega Matrixi võrgus, olenemata sellest, kas nad kasutavad Elementi või mõnda muud Matrixi rakendust, ja isegi kui nad kasutavad teistsugust suhtlussüsteemi nagu Slack, IRC või XMPP.
+Üliturvaline
+Tõeline läbiv krüptimine (ainult vestluses osalejad saavad sõnumeid lugeda) ja risttunnustamine vestluses osalejate tuvastamiseks.
- ÜLITURVALINE : tõeline läbiv krüptimine (ainult vestluses osalejad saavad sõnumeid lugeda) ja risttunnustamine vestluses osalejate tuvastamiseks.
+Kõik suhtlusvõimalused
+Sõnumid, hääl- ja videokõned, failide jagamine, ekraani jagamine ja terve hulk lõiminguid, roboteid ja vidinaid. Loo tubasid, kogukondi, hoia ühendust ja saa asjad aetud.
- KÕIK SUHTLUSVÕIMALUSED: sõnumid, hääl- ja videokõned, failide jagamine, ekraani jagamine ja terve hulk lõiminguid, roboteid ja vidinaid. Loo tubasid, kogukondi, hoia ühendust ja saa asjad aetud.
-
- KÕIKJAL, KUS VIIBITE: saad suhelda kõigis oma seadmetes ja ka veebis aadressil https://app.element.io ning sealjuures täielikult sünkroonitud sõnumite ajalooga.
+Jätka sealt, kus pooleli jäid
+Saad suhelda kõigis oma seadmetes ja ka veebis aadressil https://app.element.io ning sealjuures täielikult sünkroonitud sõnumite ajalooga.
diff --git a/fastlane/metadata/android/et/short_description.txt b/fastlane/metadata/android/et/short_description.txt
index 4075c1f7cf..5352464a7a 100644
--- a/fastlane/metadata/android/et/short_description.txt
+++ b/fastlane/metadata/android/et/short_description.txt
@@ -1 +1 @@
-Turvalised ning hajutatud vestlused ja VoIP-kõned. Sinu suhtlus on üliturvaline.
+Vestlus- ja koostöörakendus: krüptitud sõnumid, rühmavestlused ja videokõned
diff --git a/fastlane/metadata/android/et/title.txt b/fastlane/metadata/android/et/title.txt
index f74f9ff18f..b0bf39ba23 100644
--- a/fastlane/metadata/android/et/title.txt
+++ b/fastlane/metadata/android/et/title.txt
@@ -1 +1 @@
-Element (varem Riot.im)
+Element - turvaline sõnumiklient
diff --git a/fastlane/metadata/android/fi/full_description.txt b/fastlane/metadata/android/fi/full_description.txt
index 947d19ce3d..ac02bc3b42 100644
--- a/fastlane/metadata/android/fi/full_description.txt
+++ b/fastlane/metadata/android/fi/full_description.txt
@@ -1,30 +1,39 @@
-Element on uudenlainen viestinsovellus, joka:
+Element on turvallinen pikaviesti- ja tiimityösovellus joka sopii mainiosti ryhmäkeskusteluihin etätöissä. Sovellus käyttää päästä päähän -salausta ja tarjoaa videoneuvottelun, tiedostojen jakamisen ja äänipuhelut.
-1. Antaa sinun päättää yksityisyydestäsi
-2. Antaa sinun kommunikoida kenen tahansa kanssa Matrix-verkossa ja jopa sen ulkopuolella siltaamalla sovelluksiin, kuten Slack
-3. Suojaa sinua mainonnalta, tietojen keräämiseltä ja suljetuilta alustoilta
-4. Suojaa sinut päästä päähän -salauksella sekä ristiin varmentamisella muiden todentamiseksi
+Elementin ominaisuuksia:
+- Edistyneet viestintätyökalut
+- Turvallisempaa yritysviestintää täysin salatuilla viesteillä, myös etätyöntekijöille
+- Hajautettu keskustelu, joka perustuu avoimen lähdekoodin Matrix-teknologiaan
+- Turvallinen tiedostojen jakaminen datan salauksella
+- Videoneuvottelut VoIP:lla ja näytön jakamisella
+- Helppo integraatio tiimityövälineisiin, projektinhallintatyökaluihin, VoIP-palveluihin ja muihin ryhmäviestimiin
-Element eroaa täysin muista viestintäsovelluksista, koska se on hajautettu ja avointa lähdekoodia.
+Element on täysin erilainen kuin muut viestintä- ja yhteistyösovellukset. Se toimii Matrixilla, avoimella turvallisen ja hajautetun viestinnän verkostolla. Palvelimen ylläpitäminen itse on mahdollista, jos haluaa tietonsa ja viestinsä täysin hallintaansa.
-Element antaa sinun isännöidä itse - tai valita palveluntarjoajan - jotta sinulla on yksityisyys ja voit hallita tietojasi sekä keskustelujasi. Se antaa sinulle pääsyn avoimeen verkkoon, joten et jää juttelemaan vain toisten Elementin käyttäjien kanssa. Se on myös hyvin turvallinen.
+Yksityisyys ja salattu viestintä
+Element protects you from unwanted ads, data mining and walled gardens. It also secures all your data, one-to-one video and voice communication through end-to-end encryption and cross-signed device verification.
-Element pystyy tekemään kaiken tämän, koska se toimii Matrixilla - avoimella, hajautetun viestinnän standardilla.
+Element gives you control over your privacy while allowing you to communicate securely with anyone on the Matrix network, or other business collaboration tools by integrating with apps such as Slack.
-Element antaa sinulle päätösvallan antamalla sinun valita, kuka isännöi keskustelujasi. Element-sovelluksessa voit valita isännän eri tavoin:
+Voit ylläpitää omaa palvelinta
+To allow more control of your sensitive data and conversations, Element can be self-hosted or you can choose any Matrix-based host - the standard for open source, decentralized communication. Element gives you privacy, security compliance and integration flexibility.
-1. Hanki ilmainen tili Matrix-kehittäjien ylläpitämällä matrix.org-palvelimella tai valitse tuhansista vapaaehtoisten ylläpitämistä julkisista palvelimista.
-2. Isännöi tiliäsi itse ylläpitämällä palvelinta omalla laitteellasi
-3. Luo tili sinua varten tehdyllä palvelimella tilaamalla Element Matrix Services -palvelu
+Hallitse omia tietojasi
+You decide where to keep your data and messages. Without the risk of data mining or access from third parties.
-Miksi valita Element?
+Element puts you in control in different ways:
+1. Get a free account on the matrix.org public server hosted by the Matrix developers, or choose from thousands of public servers hosted by volunteers
+2. Self-host your account by running a server on your own IT infrastructure
+3. Sign up for an account on a custom server by simply subscribing to the Element Matrix Services hosting platform
-OMAT TIEDOT: Sinä päätät, missä tietosi ja viestisi säilytetään. Sinä määräät, ei jokin jättiyhtiö, joka tutkii tietojasi tai antaa niitä kolmansille osapuolille.
+Avointa viestintää ja yhteistyötä
+Voit keskustella kenen tahansa kanssa Matrix-verkossa, riippumatta siitä käyttääkö tämä Elementiä, jotain muuta Matrix-sovellusta tai jopa muuta viestintäsovellusta.
-AVOINTA VIESTINTÄÄ JA YHTEISTYÖTÄ: Voit keskustella kaikkien muiden Matrix-verkon käyttäjien kanssa, riippumatta siitä käyttävätkö he Elementiä tai muuta Matrix-sovellusta, ja vaikka he käyttäisivät eri viestijärjestelmiä, kuten Slack, IRC tai XMPP.
+Todella turvallinen
+Real end-to-end encryption (only those in the conversation can decrypt messages), and cross-signed device verification.
-ERITTÄIN TURVALLINEN: Vahva päästä päähän -salaus (vain keskustelussa olevat voivat purkaa viestien salauksen), ja ristiin varmentaminen keskustelun osallistujien laitteiden tarkistamiseksi.
+Kattavaa viestintää ja integraatioita
+Viestit, ääni- ja videopuhelut, tiedostojen jakaminen, näytön jakaminen ja koko joukko integraatioita, botteja ja sovelmia. Luo huoneita ja yhteisöjä, pidä yhteyttä ja hoida asiasi.
-KATTAVAA VIESTINTÄÄ: Viestit, ääni- ja videopuhelut, tiedostojen jakaminen, näytön jakaminen ja koko joukko integraatioita, botteja ja sovelmia. Rakenna huoneita ja yhteisöjä, pidä yhteyttä ja hoida asiasi.
-
-MISSÄ TAHANSA OLETKIN: Pidä yhteyttä missä tahansa, täysin synkronoidun viestihistorian kautta kaikilla laitteillasi ja verkossa osoitteessa https://app.element.io.
+Jatka siitä mihin jäit
+Stay in touch wherever you are with fully synchronised message history across all your devices and on the web at https://app.element.io
diff --git a/fastlane/metadata/android/fi/short_description.txt b/fastlane/metadata/android/fi/short_description.txt
index 64f35a7dff..0f5314071d 100644
--- a/fastlane/metadata/android/fi/short_description.txt
+++ b/fastlane/metadata/android/fi/short_description.txt
@@ -1 +1 @@
-Turvallista, hajautettua keskustelua ja VoIP-puheluita. Pidä tietosi turvassa.
+Ryhmäviestin - salattua viestintää, ryhmäkeskusteluja ja videopuheluita
diff --git a/fastlane/metadata/android/fi/title.txt b/fastlane/metadata/android/fi/title.txt
index 8cda14e3c8..080d4020d0 100644
--- a/fastlane/metadata/android/fi/title.txt
+++ b/fastlane/metadata/android/fi/title.txt
@@ -1 +1 @@
-Element (aiemmin Riot.im)
+Element - Turvallinen viestin
diff --git a/fastlane/metadata/android/fr/changelogs/40101020.txt b/fastlane/metadata/android/fr/changelogs/40101020.txt
new file mode 100644
index 0000000000..7bce8ac19a
--- /dev/null
+++ b/fastlane/metadata/android/fr/changelogs/40101020.txt
@@ -0,0 +1,2 @@
+Principaux changements pour cette version : amélioration des performances et corrections de bugs !
+Intégralité des changements : https://github.com/vector-im/element-android/releases/tag/v1.1.2
diff --git a/fastlane/metadata/android/fr/changelogs/40101030.txt b/fastlane/metadata/android/fr/changelogs/40101030.txt
new file mode 100644
index 0000000000..93f0b9e7fb
--- /dev/null
+++ b/fastlane/metadata/android/fr/changelogs/40101030.txt
@@ -0,0 +1,2 @@
+Principaux changements pour cette version : amélioration des performances et corrections de bugs !
+Intégralité des changements : https://github.com/vector-im/element-android/releases/tag/v1.1.3
diff --git a/fastlane/metadata/android/fr/changelogs/40101040.txt b/fastlane/metadata/android/fr/changelogs/40101040.txt
new file mode 100644
index 0000000000..0af0cf55d8
--- /dev/null
+++ b/fastlane/metadata/android/fr/changelogs/40101040.txt
@@ -0,0 +1,2 @@
+Principaux changements pour cette version : amélioration des performances et corrections de bugs !
+Intégralité des changements : https://github.com/vector-im/element-android/releases/tag/v1.1.4
diff --git a/fastlane/metadata/android/fr/changelogs/40101050.txt b/fastlane/metadata/android/fr/changelogs/40101050.txt
new file mode 100644
index 0000000000..dd6e8468af
--- /dev/null
+++ b/fastlane/metadata/android/fr/changelogs/40101050.txt
@@ -0,0 +1,2 @@
+Principaux changements pour cette version : Corrections de bugs sur la 1.1.4
+Liste de tous les changements : https://github.com/vector-im/element-android/releases/tag/v1.1.5
diff --git a/fastlane/metadata/android/fr/changelogs/40101060.txt b/fastlane/metadata/android/fr/changelogs/40101060.txt
new file mode 100644
index 0000000000..e10a8aa4f3
--- /dev/null
+++ b/fastlane/metadata/android/fr/changelogs/40101060.txt
@@ -0,0 +1,2 @@
+Principaux changements pour cette version : Corrections de bugs sur la 1.1.5
+Liste de tous les changements : https://github.com/vector-im/element-android/releases/tag/v1.1.6
diff --git a/fastlane/metadata/android/fr/full_description.txt b/fastlane/metadata/android/fr/full_description.txt
index 2b17d8f846..066b94868b 100644
--- a/fastlane/metadata/android/fr/full_description.txt
+++ b/fastlane/metadata/android/fr/full_description.txt
@@ -1,30 +1,30 @@
-Element est une nouvelle application de messagerie et de collaboration qui :
+Element est une nouvelle application de messagerie et de collaboration qui :
-1) Vous place aux commandes de votre vie privée
-2) Vous permet de communiquer avec n'importe qui du réseau Matrix, et plus encore par des intégrations d'autres applications comme Slack ou Discord
-3) Vous protège de la publicité et de la collecte de données
-4) Vous sécurise grâce à du chiffrement bout-à-bout, avec de la signature croisée pour authentifier les autres utilisateurs
+1. Vous permet de préserver votre vie privée
+2. Vous permet de communiquer avec n’importe qui sur réseau Matrix, et plus encore grâce aux intégrations d’autres applications telles que Slack ou Discord
+3. Vous protège de la publicité et de la collecte de données
+4. Vous protège grâce au chiffrement de bout-à-bout et à la signature croisée pour authentifier les autres utilisateurs
-Element est complètement différent des autres applications de messagerie et de collaboration puisque l'application est décentralisée et open-source.
+Element est complètement différente des autres applications de messagerie et de collaboration puisque l’application est décentralisée et open-source.
-Element vous permet d'héberger vous-même -ou de choisir un hôte- vous permettant d'assurer votre vie privée, la propriété et le contrôle de vos données et de vos conversations. Cela vous offre l'accès à un réseau ouvert, vous n'êtes donc pas condamné à parler à d'autres utilisateurs d'Element seulement. Et c'est très sécurisé.
+Element vous permet d’héberger vous-même ou de choisir un hôte vous permettant d’assurer votre vie privée, la propriété et le contrôle de vos données et de vos conversations. Cela vous donne accès à un réseau ouvert. Vous n’êtes donc pas condamné à parler à d’autres utilisateurs d’Element seulement. Et c'est très sécurisé.
-Element peut faire tout ça car il est basé sur Matrix, le protocole standard pour la communication ouverte et décentralisée.
+Element peut faire tout ça car elle est basée sur Matrix, le protocole standard pour la communication ouverte et décentralisée.
-Element vous donne le contrôle en vous laissant choisir qui héberge vos conversations. Depuis l'application Element, vous pouvez choisir votre hôte de différentes manières :
+Element vous donne le contrôle en vous laissant choisir qui héberge vos conversations. Depuis l'application Element, vous pouvez choisir votre hôte de différentes manières :
-1) Créer un compte gratuit sur le serveur public matrix.org hébergé par les développeurs de Matrix, ou choisir parler les milliers de serveurs public hébergés par des bénévoles
-2) Héberger vous-même votre compte en installant un serveur sur votre propre machine
-3) Créer un compte sur un serveur personnalisé en souscrivant sur la plateforme d'hébergement « Element Matrix Services » (EMS)
+1. Créer un compte gratuit sur le serveur public matrix.org hébergé par les développeurs de Matrix, ou choisir parmi les milliers de serveurs public hébergés par des bénévoles
+2. Héberger vous-même votre compte en installant un serveur sur votre propre machine
+3. Créer un compte sur un serveur personnalisé en souscrivant sur la plateforme d'hébergement « Element Matrix Services » (EMS)
Pourquoi choisir Element ?
-POSSÉDEZ VOS DONNÉES : Vous décidez où conserver vos données et vos messages. Vous les possédez et vous les contrôlez, et non une MEGACORP qui mine vos données ou les donnent à des tiers
+VOS DONNÉES VOUS APPARTIENNENT : vous décidez où stocker vos données et messages. Ils vous appartiennent et vous les maîtrisez. Aucune multinationale ne viendra extraire vos données pour les envoyer au plus offrant.
-UNE MESSAGERIE OUVERTE ET COLLABORATIVE : Vous pouvez discuter avec n'importe qui sur le réseau Matrix, qu'ils utilisent Element ou une autre application basée sur Matrix, et même s'ils utilisent un système de messagerie différent comment Slack, Discord, IRC ou XMPP.
+MESSAGERIE ET COLLABORATION OUVERTES : vous pouvez discuter avec tout le réseau Matrix, qu’ils utilisent Element ou une autre application Matrix, même s’ils utilisent une autre plateforme de messagerie telle que Slack, IRC ou XMPP.
-SUPER SÉCURISÉ : Un réel chiffrement bout-à-bout (seulement ceux deux la conversation peuvent déchiffrer les messages), et une signature croisée pour vérifier les appareils des participants de la conversation.
+ULTRA SÉCURISÉ : chiffrement de bout en bout (seuls les membres d’une conversation peuvent déchiffrer les messages), et signature croisée pour vérifier les appareils de vos interlocuteurs.
-COMMUNICATION COMPLÈTE : Messagerie, appels vocaux et vidéo, transfert de fichiers, partage d'écran et un tas d'intégrations, robots et widgets. Construisez des salons, des communautés, restez en contact et accomplissez de grandes choses.
+TOUTES VOS COMMUNICATIONS : messagerie, appels audio et vidéo, partage de fichier, partage d’écran et un grand nombre d’intégrations, robots et widgets. Participez à des salons, des communautés, restez en contact et faites avancer vos projets.
-PARTOUT OÙ VOUS ÊTES : Restez connectés peu import où vous êtes avec la synchronisation complète de l'historique des messages sur tous vos appareils et sur le web sur https://app.element.io.
+PARTOUT AVEC VOUS : votre historique reste synchronisé entre tous vos appareils et sur le web sur https://element.io/app.
diff --git a/fastlane/metadata/android/fr/short_description.txt b/fastlane/metadata/android/fr/short_description.txt
index 2fb9762e97..f9d18863ce 100644
--- a/fastlane/metadata/android/fr/short_description.txt
+++ b/fastlane/metadata/android/fr/short_description.txt
@@ -1 +1 @@
-Chat & VoIP sûr et décentralisé. Gardez vos données en sécurité.
+Messagerie de groupe - messages chiffrés, groupes et appels vidéos
diff --git a/fastlane/metadata/android/fr/title.txt b/fastlane/metadata/android/fr/title.txt
index 87cbc3b858..9152e92cfa 100644
--- a/fastlane/metadata/android/fr/title.txt
+++ b/fastlane/metadata/android/fr/title.txt
@@ -1 +1 @@
-Element (anciennement Riot.im)
+Element - Messagerie sécurisée
diff --git a/fastlane/metadata/android/fy/changelogs/40100100.txt b/fastlane/metadata/android/fy/changelogs/40100100.txt
new file mode 100644
index 0000000000..dc2eda9234
--- /dev/null
+++ b/fastlane/metadata/android/fy/changelogs/40100100.txt
@@ -0,0 +1,2 @@
+Disse nije ferzje bestjit foar in grut diel út breksoplossings en ferbetteringen. Berjochten stjoere giet no in soad flugger.
+Folsleine feroaringslist: https://github.com/vector-im/element-android/releases/tag/v1.0.10
diff --git a/fastlane/metadata/android/fy/changelogs/40100110.txt b/fastlane/metadata/android/fy/changelogs/40100110.txt
new file mode 100644
index 0000000000..8249b5c409
--- /dev/null
+++ b/fastlane/metadata/android/fy/changelogs/40100110.txt
@@ -0,0 +1,2 @@
+Disse nije ferzje bestjit foar in grut diel út brûkersinterfaasje en brûkersûnderfingsferbetteringen. No kinst freonen útnûgje, en gau DM's meitsje troch QR koades te scannen.
+Folsleine feroaringslist: https://github.com/vector-im/element-android/releases/tag/v1.0.11
diff --git a/fastlane/metadata/android/fy/changelogs/40100120.txt b/fastlane/metadata/android/fy/changelogs/40100120.txt
new file mode 100644
index 0000000000..9605ce2a75
--- /dev/null
+++ b/fastlane/metadata/android/fy/changelogs/40100120.txt
@@ -0,0 +1,2 @@
+Haadferoaring yn disse ferzje: URL ynsjen, nij emoji toetseboerd, nij keamer ynstellings moochlikheden, en snie foar kryst.
+Folsleine feroaringslist: https://github.com/vector-im/element-android/releases/tag/v1.0.12
diff --git a/fastlane/metadata/android/fy/changelogs/40100130.txt b/fastlane/metadata/android/fy/changelogs/40100130.txt
new file mode 100644
index 0000000000..ebc7285193
--- /dev/null
+++ b/fastlane/metadata/android/fy/changelogs/40100130.txt
@@ -0,0 +1,2 @@
+Haadferoaring yn disse ferzje: URL ynsjen, nij emoji toetseboerd, nij keamer ynstellings moochlikheden, en snie foar kryst.
+Folsleine feroaringslist: https://github.com/vector-im/element-android/releases/tag/v1.0.13
diff --git a/fastlane/metadata/android/fy/changelogs/40100140.txt b/fastlane/metadata/android/fy/changelogs/40100140.txt
new file mode 100644
index 0000000000..6886848889
--- /dev/null
+++ b/fastlane/metadata/android/fy/changelogs/40100140.txt
@@ -0,0 +1,2 @@
+Haadferoaring yn disse ferzje: Keamer fjochten feroarje, automatysk ljocht/tsjuster tema, en breksferbetteringen.
+Folsleine feroaringslist: https://github.com/vector-im/element-android/releases/tag/v1.0.14
diff --git a/fastlane/metadata/android/fy/changelogs/40100150.txt b/fastlane/metadata/android/fy/changelogs/40100150.txt
new file mode 100644
index 0000000000..d291da0475
--- /dev/null
+++ b/fastlane/metadata/android/fy/changelogs/40100150.txt
@@ -0,0 +1,2 @@
+Haadferoaring yn disse ferzje: Stipe foar sosjaal ynlogge!
+Folsleine feroaringslist: https://github.com/vector-im/element-android/releases/tag/v1.0.15
diff --git a/fastlane/metadata/android/fy/changelogs/40100160.txt b/fastlane/metadata/android/fy/changelogs/40100160.txt
new file mode 100644
index 0000000000..eb2be2d09c
--- /dev/null
+++ b/fastlane/metadata/android/fy/changelogs/40100160.txt
@@ -0,0 +1,2 @@
+Haadferoaring yn disse ferzje: Stipe foar sosjaal ynlogge!
+Folsleine feroaringslist: https://github.com/vector-im/element-android/releases/tag/v1.0.15 and https://github.com/vector-im/element-android/releases/tag/v1.0.16
diff --git a/fastlane/metadata/android/fy/changelogs/40100170.txt b/fastlane/metadata/android/fy/changelogs/40100170.txt
new file mode 100644
index 0000000000..281b087584
--- /dev/null
+++ b/fastlane/metadata/android/fy/changelogs/40100170.txt
@@ -0,0 +1,2 @@
+Haadferoaring yn disse ferzje: Breksoplossings!
+Folsleine feroaringslist: https://github.com/vector-im/element-android/releases/tag/v1.0.17
diff --git a/fastlane/metadata/android/fy/changelogs/40101000.txt b/fastlane/metadata/android/fy/changelogs/40101000.txt
new file mode 100644
index 0000000000..a860b7b468
--- /dev/null
+++ b/fastlane/metadata/android/fy/changelogs/40101000.txt
@@ -0,0 +1,2 @@
+Haadferoaring yn disse ferzje: VoIP (lûds en video skilje yn DM) ferbetteringen en breksoplossings!
+Folsleine feroaringslist: https://github.com/vector-im/element-android/releases/tag/v1.1.0
diff --git a/fastlane/metadata/android/fy/changelogs/40101010.txt b/fastlane/metadata/android/fy/changelogs/40101010.txt
new file mode 100644
index 0000000000..2369fc4d22
--- /dev/null
+++ b/fastlane/metadata/android/fy/changelogs/40101010.txt
@@ -0,0 +1,2 @@
+Haadferoaring yn disse ferzje: Prestaasje feroaringen en breksoplossings!
+Folsleine feroaringslist: https://github.com/vector-im/element-android/releases/tag/v1.1.1
diff --git a/fastlane/metadata/android/fy/changelogs/40101020.txt b/fastlane/metadata/android/fy/changelogs/40101020.txt
new file mode 100644
index 0000000000..13aa172071
--- /dev/null
+++ b/fastlane/metadata/android/fy/changelogs/40101020.txt
@@ -0,0 +1,2 @@
+Haadferoaring yn disse ferzje: Prestaasje feroaringen en breksoplossings!
+Folsleine feroaringslist: https://github.com/vector-im/element-android/releases/tag/v1.1.2
diff --git a/fastlane/metadata/android/fy/changelogs/40101030.txt b/fastlane/metadata/android/fy/changelogs/40101030.txt
new file mode 100644
index 0000000000..595cbdf104
--- /dev/null
+++ b/fastlane/metadata/android/fy/changelogs/40101030.txt
@@ -0,0 +1,2 @@
+Haadferoaring yn disse ferzje: Prestaasje feroaringen en breksoplossings!
+Folsleine feroaringslist: https://github.com/vector-im/element-android/releases/tag/v1.1.3
diff --git a/fastlane/metadata/android/fy/changelogs/40101040.txt b/fastlane/metadata/android/fy/changelogs/40101040.txt
new file mode 100644
index 0000000000..e86e7ce3e3
--- /dev/null
+++ b/fastlane/metadata/android/fy/changelogs/40101040.txt
@@ -0,0 +1,2 @@
+Haadferoaring yn disse ferzje: Prestaasje feroaringen en breksoplossings!
+Folsleine feroaringslist: https://github.com/vector-im/element-android/releases/tag/v1.1.4
diff --git a/fastlane/metadata/android/fy/changelogs/40101050.txt b/fastlane/metadata/android/fy/changelogs/40101050.txt
new file mode 100644
index 0000000000..fdf5f98eb7
--- /dev/null
+++ b/fastlane/metadata/android/fy/changelogs/40101050.txt
@@ -0,0 +1,2 @@
+Haadferoaring yn disse ferzje: feroaringen foar 1.1.4
+Folsleine feroaringslist: https://github.com/vector-im/element-android/releases/tag/v1.1.5
diff --git a/fastlane/metadata/android/fy/changelogs/40101060.txt b/fastlane/metadata/android/fy/changelogs/40101060.txt
new file mode 100644
index 0000000000..47ac5692d5
--- /dev/null
+++ b/fastlane/metadata/android/fy/changelogs/40101060.txt
@@ -0,0 +1,2 @@
+Haadferoaring yn disse ferzje: feroaringen foar 1.1.5
+Folsleine feroaringslist: https://github.com/vector-im/element-android/releases/tag/v1.1.6
diff --git a/fastlane/metadata/android/fy/short_description.txt b/fastlane/metadata/android/fy/short_description.txt
new file mode 100644
index 0000000000..ddc559b59c
--- /dev/null
+++ b/fastlane/metadata/android/fy/short_description.txt
@@ -0,0 +1 @@
+Groepsberjochtetsjinst - fersifere berjochten, groeps petearen en fideo skilje
diff --git a/fastlane/metadata/android/fy/title.txt b/fastlane/metadata/android/fy/title.txt
new file mode 100644
index 0000000000..c4b5b596fc
--- /dev/null
+++ b/fastlane/metadata/android/fy/title.txt
@@ -0,0 +1 @@
+Element - Feilige Berjochtetsjinst
diff --git a/fastlane/metadata/android/hu/changelogs/40100130.txt b/fastlane/metadata/android/hu/changelogs/40100130.txt
index e1b044f4e5..47ce2690f4 100644
--- a/fastlane/metadata/android/hu/changelogs/40100130.txt
+++ b/fastlane/metadata/android/hu/changelogs/40100130.txt
@@ -1,2 +1,2 @@
Főbb változtatások ebben a verzióban: URL előnézet, új emoji billentyűzet, új szoba beállitási lehetőségek, és hó karácsonyra!
-Teljes változásnapló: https://github.com/vector-im/element-android/releases/tag/v1.0.12
+Teljes változásnapló: https://github.com/vector-im/element-android/releases/tag/v1.0.13
diff --git a/fastlane/metadata/android/hu/changelogs/40100140.txt b/fastlane/metadata/android/hu/changelogs/40100140.txt
new file mode 100644
index 0000000000..1b86da9ab1
--- /dev/null
+++ b/fastlane/metadata/android/hu/changelogs/40100140.txt
@@ -0,0 +1,2 @@
+Fő változás ebben a verzióban: Szoba jogosultságok szerkesztése, automatikus sötét/világos téma és sok hibajavítás.
+Teljes változásnapló: https://github.com/vector-im/element-android/releases/tag/v1.0.14
diff --git a/fastlane/metadata/android/hu/changelogs/40100150.txt b/fastlane/metadata/android/hu/changelogs/40100150.txt
new file mode 100644
index 0000000000..b48fd6a0d7
--- /dev/null
+++ b/fastlane/metadata/android/hu/changelogs/40100150.txt
@@ -0,0 +1,2 @@
+Fő változás ebben a verzióban: Közösségi hálózatos bejelentkezés támogatása
+Teljes változásnapló: https://github.com/vector-im/element-android/releases/tag/v1.0.15
diff --git a/fastlane/metadata/android/hu/changelogs/40100160.txt b/fastlane/metadata/android/hu/changelogs/40100160.txt
new file mode 100644
index 0000000000..bb983ed5e8
--- /dev/null
+++ b/fastlane/metadata/android/hu/changelogs/40100160.txt
@@ -0,0 +1,2 @@
+Fő változás ebben a verzióban: Közösségi hálózatos bejelentkezés
+Teljes változásnapló: https://github.com/vector-im/element-android/releases/tag/v1.0.15 and https://github.com/vector-im/element-android/releases/tag/v1.0.16
diff --git a/fastlane/metadata/android/hu/changelogs/40100170.txt b/fastlane/metadata/android/hu/changelogs/40100170.txt
new file mode 100644
index 0000000000..806470d74e
--- /dev/null
+++ b/fastlane/metadata/android/hu/changelogs/40100170.txt
@@ -0,0 +1,2 @@
+Fő változás ebben a verzióban: Hibajavítás!
+Teljes változásnapló: https://github.com/vector-im/element-android/releases/tag/v1.0.17
diff --git a/fastlane/metadata/android/hu/changelogs/40101000.txt b/fastlane/metadata/android/hu/changelogs/40101000.txt
new file mode 100644
index 0000000000..0bc4f5d49f
--- /dev/null
+++ b/fastlane/metadata/android/hu/changelogs/40101000.txt
@@ -0,0 +1,2 @@
+Fő változás ebben a verzióban: VoIP (hang és videóhívás közvetlen beszélgetésekben) fejlesztés és hibajavítás
+Teljes változásnapló: https://github.com/vector-im/element-android/releases/tag/v1.1.0
diff --git a/fastlane/metadata/android/hu/changelogs/40101010.txt b/fastlane/metadata/android/hu/changelogs/40101010.txt
new file mode 100644
index 0000000000..503fc0ab2f
--- /dev/null
+++ b/fastlane/metadata/android/hu/changelogs/40101010.txt
@@ -0,0 +1,2 @@
+Fő változás ebben a verzióban: sebesség javítás és hibajavítás
+Teljes változásnapló: https://github.com/vector-im/element-android/releases/tag/v1.1.1
diff --git a/fastlane/metadata/android/hu/changelogs/40101020.txt b/fastlane/metadata/android/hu/changelogs/40101020.txt
new file mode 100644
index 0000000000..04d67ac5ae
--- /dev/null
+++ b/fastlane/metadata/android/hu/changelogs/40101020.txt
@@ -0,0 +1,2 @@
+Fő változás ebben a verzióban: sebesség javítás és hibajavítás
+Teljes változásnapló: https://github.com/vector-im/element-android/releases/tag/v1.1.2
diff --git a/fastlane/metadata/android/hu/changelogs/40101030.txt b/fastlane/metadata/android/hu/changelogs/40101030.txt
new file mode 100644
index 0000000000..4d0e46739e
--- /dev/null
+++ b/fastlane/metadata/android/hu/changelogs/40101030.txt
@@ -0,0 +1,2 @@
+Fő változás ebben a verzióban: sebesség javítás és hibajavítás
+Teljes változásnapló: https://github.com/vector-im/element-android/releases/tag/v1.1.3
diff --git a/fastlane/metadata/android/hu/changelogs/40101040.txt b/fastlane/metadata/android/hu/changelogs/40101040.txt
new file mode 100644
index 0000000000..1c6921f0d5
--- /dev/null
+++ b/fastlane/metadata/android/hu/changelogs/40101040.txt
@@ -0,0 +1,2 @@
+Fő változás ebben a verzióban: sebesség javítás és hibajavítás
+Teljes változásnapló: https://github.com/vector-im/element-android/releases/tag/v1.1.4
diff --git a/fastlane/metadata/android/hu/changelogs/40101050.txt b/fastlane/metadata/android/hu/changelogs/40101050.txt
new file mode 100644
index 0000000000..c937bb9215
--- /dev/null
+++ b/fastlane/metadata/android/hu/changelogs/40101050.txt
@@ -0,0 +1,2 @@
+Fő változás ebben a verzióban: javítás az 1.1.4 verzióhoz
+Teljes változásnapló: https://github.com/vector-im/element-android/releases/tag/v1.1.5
diff --git a/fastlane/metadata/android/hu/changelogs/40101060.txt b/fastlane/metadata/android/hu/changelogs/40101060.txt
new file mode 100644
index 0000000000..a9b37e66a9
--- /dev/null
+++ b/fastlane/metadata/android/hu/changelogs/40101060.txt
@@ -0,0 +1,2 @@
+Fő változás ebben a verzióban: javítás az 1.1.5 verzióhoz
+Teljes változásnapló: https://github.com/vector-im/element-android/releases/tag/v1.1.6
diff --git a/fastlane/metadata/android/hu/changelogs/40101070.txt b/fastlane/metadata/android/hu/changelogs/40101070.txt
new file mode 100644
index 0000000000..4acfbea1ea
--- /dev/null
+++ b/fastlane/metadata/android/hu/changelogs/40101070.txt
@@ -0,0 +1,2 @@
+Fő változás ebben a verzióban: béta állapotú Tér támogatás. Videó tömörítés küldés előtt.
+Teljes változásnapló: https://github.com/vector-im/element-android/releases/tag/v1.1.7
diff --git a/fastlane/metadata/android/hu/full_description.txt b/fastlane/metadata/android/hu/full_description.txt
index b75f259d02..032346ccb8 100644
--- a/fastlane/metadata/android/hu/full_description.txt
+++ b/fastlane/metadata/android/hu/full_description.txt
@@ -1,30 +1,40 @@
-Az Element egy új üzenetküldő, és csapatmunka alkalmazás, amivel
+Element egy biztonságos üzenetküldő és csapatmunka támogató alkalmazás ami ideális távoli munkavégzés közben csoportos csevegéshez. Az alkalmazás végpontok közötti titkosítást használ videó konferenciához, fájl megosztáshoz és videó hivásokhoz.
-1. A te kezedben van az irányítás a saját adataid fölött, hogy megőrizhesd a magánszférádat
-2. Akárkivel beszélgethetsz a Matrix hálózatban, sőt még azon kívül is, például olyan alkalmazások integrálásával, mint a Slack
-3. Megvédheted magad a hirdetésektől, adatbányászattól, és a nagy cégek megoldásaiba való bezártságtól
-4. Biztonságosan beszélgethetsz, a végpontok közötti titkosításnak köszönhetően, az eszközök megbízhatóságát az eszköz-közti hitelesítéssel garantálva
+Element tulajdonságai:
+- Fejlett online kommunikációs eszköz
+- Teljesen titkosított üzenetküldés biztonságos céges kommunikációt kínál még a távdolgozóknak is
+- Elosztott csevegés a Matrix nyílt forráskódú keretrendszer felhasználásával
+- Bizontságos fájl megosztás titkosítottan projektek kezeléséhez
+- Videó hívás VoIP-pal és képernyőmegosztással
+- Könnyen integrálható a kedvenc online kollaborációs eszközöddel, projekt menedzsment eszközzel, VoIP szolgáltatással vagy más csoport üzenetküldő alkalmazással
-Az Element teljesen más, mint a többi üzenetküldő és csapatmunka alkalmazás, mert nyílt forráskódú, és decentralizált (nem központilag irányított).
+Element teljesen más mint a többi üzenetküldő alkalmazás. Matrixot használ, egy nyílt hálózatot a decentralizált biztonságos kommunikációhoz. Lehetőséget ad saját szerver üzemeltetésére ami maximális tulajdont és kontrollt biztosít az adatok fölött.
-Az Element lehetővé teszi, hogy saját szervert futtass - vagy válassz egy szolgáltatót - így te birtoklod az adataidat, ezáltal megőrizve a magánszférád és a biztonságod. Egy nyitott hálózathoz ad hozzáférést, így nem csak a többi Element felhasználóval tudsz beszélgetni, hanem másokkal is. Ráadásul nagyon biztonságos.
+Magánélet védelme és titkosított üzenetküldés
+Element megóv a kéretlen hirdetésektől, adatbányászattól és a különböző szigetszerű megoldásoktól. Minden adatot biztonságba helyez, egy az egybe videó és hang kommunikáció végpontok között titkosítva ahol az eszközök hitelesítve vannak.
-Az Element-tel azért válik mindez lehetővé, mert a Matrix hálózatra épül - egy nyílt, decentralizált kommunikációs szabványra.
+Element a kezedbe adja az adatvédelmi irányítást miközben bárkivel kommunikálhatsz a Matrix hálózatban vagy más üzleti kollaborációs eszközzel ami integrálva van, mint amilyen a Slack.
-Az Element a te kezedbe adja az irányítást azáltal, hogy eldöntheted, ki tárolja a beszélgetéseidet. Az Element alkalmazásból több féle szolgáltatót is választhatsz:
+Element futtatható saját szerveren
-1. Regisztrálhatsz ingyen egy fiókot a matrix.org nyilvános szerveren, amit a Matrix fejlesztői üzemeltetnek, vagy választhatsz a több ezer, ingyenes szerver közül, amit önkéntesek üzemeltetnek
-2. A saját számítógépeden is futtathatsz szervert
-3. Előfizethetsz egy saját szerverre az Element Matrix Szolgáltatások platformon
+Azért, hogy az érzékeny adatok és beszélgetések minnél inkább az irányításod alatt lehessen az Elementet saját magadnak üzemeltetheted vagy választhatsz bármely Matrixon alapuló - szabványos nyílt forráskódú és decentralizált kommunikáció - szoláltató közül. Element adatvédelmet, biztonságot és rugalmas integrációkat biztosít.
-Miért jó az Element-et választani?
+A te adatod a tiéd
+Te döntöd el, hogy hol tárolod az adataidat és üzeneteidet. Adatbányászat vagy harmadik fél hozzáférésének kockázata nélkül.
-ADATAID MEGVÉDÉSE: Eldöntheted, hol tárold az adataid és üzeneteid. A te tulajdonodban van, nem valami megacégnél, ami bányássza az adataid, vagy továbbadja másoknak.
+Element többféle képpen adja vissza az irányítást:
+1. Szerezz egy ingyenes hozzáférést a matrix.org nyilvános szerverre amit a Matrix fejlesztők üzemeltetnek vagy válassz a több ezer önkéntesek által üzemeltetett nyilvános szerverből
+2. Üzemeltess szerver magadnak a saját infrastruktúrádon
+3. Iratkozz fel egy egyedi szerverre az Element Matrix Services platformon
-NYÍLT BESZÉLGETÉS, ÉS CSAPATMUNKA: Akárkivel cseveghetsz a Matrix hálózatban, akár az Element-et használják, akár valamilyen másik Matrix alkalmazást, de még akkor is, ha egy másik csevegő hálózatot használnak, olyat, mint például a Slack, IRC, vagy az XMPP.
+Nyílt üzenetküldés és kollaboráció
+Bárkivel beszélgethetsz a Matrix hálózaton, akár az Elementet használja akár egy másik Matrix alkalmazást használ vagy akár egy eltérő üzenetküldőt.
-SZUPER-BIZTONSÁGOS: Valódi, végpontok közötti titkosítás (csak a beszélgetés résztvevői tudják elolvasni az üzeneteket), és eszköz-közti hitelesítés, hogy ellenőrizhesd a résztvevők eszközeit.
+Fantasztikusan biztonságos
+Igazi végpontok között titkosítás (csak a beszélgetésben résztvevők tudják visszafejteni) és hitelesítés eszközök közötti aláírásokkal.
-TELJES KOMMUNIKÁCIÓ: Üzenetküldés, hang- és videóhívások, fájlmegosztás, képernyőmegosztás, és egy rakás integráció, bot, és widget. Hozz létre szobákat, közösségeket, maradj elérhető, és végezzétek el a feladatokat.
+Teljes kommunikáció és integráció
+Üzenetküldés, hang és videóhívás, fájl megosztás, képernyő megosztás és egy csomó integráció, botok és kisalkalmazások. Építs szobákat, közösségeket, maradj kapcsolatban és végezz el dolgokat.
-AKÁRHOL, AHOL CSAK SZÜKSÉG VAN RÁ: Akárhol is vagy, maradj elérhető, a teljes mértékben szinkronizált beszélgetésekkel az összes eszközödön, és a weben a https://app.element.io oldalon.
+Vedd fel a fonalat
+Maradj kapcsolatban bárhol minden eszközödön a szinkronizált üzenetekkel és a weben a https://app.element.io oldallal
diff --git a/fastlane/metadata/android/hu/short_description.txt b/fastlane/metadata/android/hu/short_description.txt
index 89f7c13f54..2dfe14c516 100644
--- a/fastlane/metadata/android/hu/short_description.txt
+++ b/fastlane/metadata/android/hu/short_description.txt
@@ -1 +1 @@
-Biztonságos, decentralizált chat és VoIP. Tartsd az adataid biztonságban.
+Csoportos üzenetküldő - titkosított üzenetek, videó hívások
diff --git a/fastlane/metadata/android/hu/title.txt b/fastlane/metadata/android/hu/title.txt
index 8e493d2d08..c463dea393 100644
--- a/fastlane/metadata/android/hu/title.txt
+++ b/fastlane/metadata/android/hu/title.txt
@@ -1 +1 @@
-Element (régebben Riot.im)
+Element - Biztonságos üzenetküldő
diff --git a/fastlane/metadata/android/it/changelogs/40101020.txt b/fastlane/metadata/android/it/changelogs/40101020.txt
new file mode 100644
index 0000000000..21057629e3
--- /dev/null
+++ b/fastlane/metadata/android/it/changelogs/40101020.txt
@@ -0,0 +1,2 @@
+Modifiche principali in questa versione: prestazioni migliorate e correzione di errori!
+Cronologia completa: https://github.com/vector-im/element-android/releases/tag/v1.1.2
diff --git a/fastlane/metadata/android/it/changelogs/40101030.txt b/fastlane/metadata/android/it/changelogs/40101030.txt
new file mode 100644
index 0000000000..a62c4a0736
--- /dev/null
+++ b/fastlane/metadata/android/it/changelogs/40101030.txt
@@ -0,0 +1,2 @@
+Modifiche principali in questa versione: prestazioni migliorate e correzioni di errori!
+Cronologia completa: https://github.com/vector-im/element-android/releases/tag/v1.1.3
diff --git a/fastlane/metadata/android/it/changelogs/40101040.txt b/fastlane/metadata/android/it/changelogs/40101040.txt
new file mode 100644
index 0000000000..93aac046a1
--- /dev/null
+++ b/fastlane/metadata/android/it/changelogs/40101040.txt
@@ -0,0 +1,2 @@
+Modifiche principali in questa versione: prestazioni migliorate e correzione di errori!
+Cronologia completa: https://github.com/vector-im/element-android/releases/tag/v1.1.4
diff --git a/fastlane/metadata/android/it/changelogs/40101050.txt b/fastlane/metadata/android/it/changelogs/40101050.txt
new file mode 100644
index 0000000000..7fa5ba20df
--- /dev/null
+++ b/fastlane/metadata/android/it/changelogs/40101050.txt
@@ -0,0 +1,2 @@
+Modifiche principali in questa versione: correzioni per la 1.1.4
+Cronologia completa: https://github.com/vector-im/element-android/releases/tag/v1.1.5
diff --git a/fastlane/metadata/android/it/changelogs/40101060.txt b/fastlane/metadata/android/it/changelogs/40101060.txt
new file mode 100644
index 0000000000..d915bf2d8f
--- /dev/null
+++ b/fastlane/metadata/android/it/changelogs/40101060.txt
@@ -0,0 +1,2 @@
+Modifiche principali in questa versione: correzioni per la 1.1.5
+Cronologia completa: https://github.com/vector-im/element-android/releases/tag/v1.1.6
diff --git a/fastlane/metadata/android/it/changelogs/40101070.txt b/fastlane/metadata/android/it/changelogs/40101070.txt
new file mode 100644
index 0000000000..6f7ffcd958
--- /dev/null
+++ b/fastlane/metadata/android/it/changelogs/40101070.txt
@@ -0,0 +1,2 @@
+Modifiche principali in questa versione: supporto beta per gli Spazi. Compressione video prima dell'invio.
+Cronologia completa: https://github.com/vector-im/element-android/releases/tag/v1.1.7
diff --git a/fastlane/metadata/android/it/full_description.txt b/fastlane/metadata/android/it/full_description.txt
index b6f7cf449c..dd7716ffbf 100644
--- a/fastlane/metadata/android/it/full_description.txt
+++ b/fastlane/metadata/android/it/full_description.txt
@@ -1,30 +1,39 @@
-Element è un nuovo tipo di app di messaggistica e collaborazione che:
+Element è sia un messenger sicuro sia un'app collaborativa per team di produttività, ideale per chat di gruppo durante il lavoro da remoto. Questa app usa una crittografia end-to-end per fornire videoconferenze, condivisione di file e videochiamate.
-1. Ti mette al controllo per preservare la tua privacy
-2. Ti lascia comunicare con chiunque nella rete Matrix e oltre, integrandosi con app come Slack
-3. Ti protegge da pubblicità, raccolta di dati e piattaforme chiuse
-4. Ti protegge con la crittografia end-to-end, con la firma incrociata per verificare gli altri
+Tra le caratteristiche di Element ci sono:
+- Strumenti di comunicazione online avanzati
+- Messaggi totalmente cifrati per consentire comunicazioni aziendali più sicure, anche per i lavoratori remoti
+- Chat decentralizzate basate sull'infrastruttura open source Matrix
+- Condivisione sicura di file con dati crittografati durante la gestione dei progetti
+- Videochiamate con "Voice over IP" e condivisione dello schermo
+- Facile integrazione con i tuoi strumenti collaborativi online preferiti, strumenti di gestione progetti, servizi VoIP ed altre app di messaggistica tra team
-Element è completamente diverso dalle altre app di messaggistica e collaborazione perchè è decentralizzato e open source.
+Element è completamente diverso dalle altre app di messaggistica e collaborazione. Funziona su Matrix, una rete aperta per messaggi sicuri e comunicazioni decentralizzate. Può essere installato in locale per dare agli utenti il pieno possesso e controllo dei propri dati e messaggi.
-Element può essere gestito in locale - o puoi scegliere un host - in modo che tu abbia privacy, possesso e controllo dei tuoi dati e conversazioni. Ti dà accesso ad una rete aperta, quindi non sei limitato a parlare solo con altri utenti Element. Ed è molto sicuro.
+Privacy e messaggi privati
+Element ti protegge da pubblicità indesiderate, dalla raccolta di dati e dalle piattaforme chiuse. Protegge tutti i tuoi dati e comunicazioni uno-ad-uno, attraverso la crittografia end-to-end e la verifica a firma incrociata tra dispositivi.
-Element può fare tutto ciò perchè funziona su Matrix - lo standard per comunicazioni aperte e decentralizzate.
+Element ti dà il controllo della tua privacy consentendoti di comunicazre in modo sicuro con chiunque nella rete di Matrix, o con altri strumenti collaborativi aziendali, integrandosi con app come Slack.
-Element ti mette al controllo lasciandoti scegliere chi gestisce il server delle tue conversazioni. Dall'app Element, hai diverse opzioni:
+Element può essere installato in locale
+Per consentire un maggiore controllo dei tuoi dati sensibili e delle conversazioni, Element può essere gestito in locale o puoi scegliere un qualsiasi host basato su Matrix - lo standard per le comunicazioni open source e decentralizzate. Element ti offre privacy, conformità alla sicurezza e flessibilità di integrazione.
+Possiedi i tuoi dati
+Decidi tu dove tenere i tuoi dati e messaggi. Senza il rischio di raccolta di dati o accessi da terze parti.
+
+Element ti mette al controllo in diversi modi:
1. Crea un account gratuito sul server pubblico matrix.org gestito dagli sviluppatori di Matrix, o scegli tra migliaia di server pubblici gestiti da volontari
-2. Gestisci autonomamente un account installando un server sul tuo hardware
+2. Gestisci autonomamente un account installando un server nella tua infrastruttura informatica
3. Registra un account su un server personalizzato iscrivendoti alla piattaforma Element Matrix Services
-Perchè scegliere Element?
+Messaggistica e collaborazioni aperte
+Puoi chattare con chiunque nella rete Matrix, sia che stiano usando Element, un'altra app Matrix, o anche un'app di messaggistica diversa.
-POSSIEDI I TUOI DATI: decidi dove tenere i tuoi dati e messaggi. Sono tuoi e li controlli tu, non qualche MEGADITTA che raccoglie i tuoi dati o ne dà l'accesso a terze parti.
+Super sicuro
+Vera crittografia end-to-end (solo chi è nella conversazione può decifrare i messaggi) e verifica di dispositivi a firma incrociata.
-MESSAGGISTICA E COLLABORAZIONE APERTE: puoi chattare con chiunque nella rete Matrix, usando Element o un'altra app Matrix, o anche se si sta usando un sistema di messaggistica diverso come Slack, IRC o XMPP.
+Comunicazioni ed integrazioni complete
+Messaggi, chiamate audio e video, condivisione file e schermo, un vasto numero di integrazioni, bot e widget. Crea stanze, comunità, resta in contatto e porta a termine gli obiettivi.
-SUPER SICURO: vera crittografia end-to-end (solo chi è nella conversazione può decifrare i messaggi) e firma incrociata per verificare i dispositivi dei partecipanti.
-
-COMUNICAZIONE COMPLETA: messaggi, chiamate audio e video, condivisione file e schermo, un vasto numero di integrazioni, bot e widget. Crea stanze, comunità, resta in contatto e porta a termine gli impegni.
-
-OVUNQUE TU SIA: resta in contatto ovunque tu sia con la cronologia dei messaggi sincronizzata tra tutti i tuoi dispositivi e in rete su https://app.element.io.
+Riprendi da dove ti eri fermato
+Resta in contatto ovunque tu sia con la cronologia dei messaggi sincronizzata tra tutti i tuoi dispositivi e in rete su https://app.element.io
diff --git a/fastlane/metadata/android/it/short_description.txt b/fastlane/metadata/android/it/short_description.txt
index 8c0c8fbee0..5050d0c1c5 100644
--- a/fastlane/metadata/android/it/short_description.txt
+++ b/fastlane/metadata/android/it/short_description.txt
@@ -1 +1 @@
-Chat e VoIP decentralizzati sicuri. Tieni lontani i tuoi dati dalle terze parti.
+Messenger di gruppo - messaggi cifrati, chat di gruppo e videochiamate
diff --git a/fastlane/metadata/android/it/title.txt b/fastlane/metadata/android/it/title.txt
index 54e3b456c7..c426a480d3 100644
--- a/fastlane/metadata/android/it/title.txt
+++ b/fastlane/metadata/android/it/title.txt
@@ -1 +1 @@
-Element (ex Riot.im)
+Element - Messaggi sicuri
diff --git a/fastlane/metadata/android/ja/changelogs/40100100.txt b/fastlane/metadata/android/ja/changelogs/40100100.txt
new file mode 100644
index 0000000000..8359a12964
--- /dev/null
+++ b/fastlane/metadata/android/ja/changelogs/40100100.txt
@@ -0,0 +1,2 @@
+今回の新バージョンでは、主にバグの修正と改善が行われています。メッセージの送信がより速くなりました。
+すべての変更履歴はこちら: https://github.com/vector-im/element-android/releases/tag/v1.0.10
diff --git a/fastlane/metadata/android/ja/changelogs/40100110.txt b/fastlane/metadata/android/ja/changelogs/40100110.txt
new file mode 100644
index 0000000000..c93db421af
--- /dev/null
+++ b/fastlane/metadata/android/ja/changelogs/40100110.txt
@@ -0,0 +1,2 @@
+今回の新バージョンでは、主にUI(ユーザーインターフェース)とUX(ユーザーエクスペリエンス)の向上が図られています。友達を招待したり、QRコードを読み取って素早くDMを作成できるようになりました。
+すべての変更履歴はこちら: https://github.com/vector-im/element-android/releases/tag/v1.0.11
diff --git a/fastlane/metadata/android/ja/changelogs/40100120.txt b/fastlane/metadata/android/ja/changelogs/40100120.txt
new file mode 100644
index 0000000000..aace2ef79f
--- /dev/null
+++ b/fastlane/metadata/android/ja/changelogs/40100120.txt
@@ -0,0 +1,2 @@
+このバージョンの主な変更点: URLプレビュー、新しい絵文字、新しいルーム設定機能、それにクリスマスには雪が!
+すべての変更履歴はこちら: https://github.com/vector-im/element-android/releases/tag/v1.0.12
diff --git a/fastlane/metadata/android/ja/changelogs/40100130.txt b/fastlane/metadata/android/ja/changelogs/40100130.txt
new file mode 100644
index 0000000000..97633621c5
--- /dev/null
+++ b/fastlane/metadata/android/ja/changelogs/40100130.txt
@@ -0,0 +1,2 @@
+このバージョンの主な変更点: URLプレビュー、新しい絵文字、新しいルーム設定機能、それにクリスマスには雪が!
+すべての変更履歴はこちら: https://github.com/vector-im/element-android/releases/tag/v1.0.13
diff --git a/fastlane/metadata/android/ja/changelogs/40100140.txt b/fastlane/metadata/android/ja/changelogs/40100140.txt
new file mode 100644
index 0000000000..c340663127
--- /dev/null
+++ b/fastlane/metadata/android/ja/changelogs/40100140.txt
@@ -0,0 +1,2 @@
+このバージョンの主な変更点: 部屋の許可、自動のテーマ切替、そして多くのバグを修正しました。
+すべての変更履歴はこちら: https://github.com/vector-im/element-android/releases/tag/v1.0.14
diff --git a/fastlane/metadata/android/ja/changelogs/40100150.txt b/fastlane/metadata/android/ja/changelogs/40100150.txt
new file mode 100644
index 0000000000..42f28c7bea
--- /dev/null
+++ b/fastlane/metadata/android/ja/changelogs/40100150.txt
@@ -0,0 +1,2 @@
+このバージョンの主な変更点: ソーシャルログインに対応しました。
+すべての変更履歴はこちら: https://github.com/vector-im/element-android/releases/tag/v1.0.15
diff --git a/fastlane/metadata/android/ja/changelogs/40100160.txt b/fastlane/metadata/android/ja/changelogs/40100160.txt
new file mode 100644
index 0000000000..8b5196998a
--- /dev/null
+++ b/fastlane/metadata/android/ja/changelogs/40100160.txt
@@ -0,0 +1,2 @@
+このバージョンの主な変更点: パフォーマンスの向上とバグの修正!
+すべての変更履歴はこちら: https://github.com/vector-im/element-android/releases/tag/v1.0.15 and https://github.com/vector-im/element-android/releases/tag/v1.0.16
diff --git a/fastlane/metadata/android/ja/changelogs/40100170.txt b/fastlane/metadata/android/ja/changelogs/40100170.txt
new file mode 100644
index 0000000000..586b01cb2b
--- /dev/null
+++ b/fastlane/metadata/android/ja/changelogs/40100170.txt
@@ -0,0 +1,2 @@
+このバージョンの主な変更点: バグの修正!
+すべての変更履歴はこちら: https://github.com/vector-im/element-android/releases/tag/v1.0.17
diff --git a/fastlane/metadata/android/ja/changelogs/40101000.txt b/fastlane/metadata/android/ja/changelogs/40101000.txt
new file mode 100644
index 0000000000..25bbd7ab87
--- /dev/null
+++ b/fastlane/metadata/android/ja/changelogs/40101000.txt
@@ -0,0 +1,2 @@
+このバージョンの主な変更点: パフォーマンスの向上とバグの修正!
+すべての変更履歴はこちら: https://github.com/vector-im/element-android/releases/tag/v1.1.0
diff --git a/fastlane/metadata/android/ja/changelogs/40101010.txt b/fastlane/metadata/android/ja/changelogs/40101010.txt
new file mode 100644
index 0000000000..35ba933069
--- /dev/null
+++ b/fastlane/metadata/android/ja/changelogs/40101010.txt
@@ -0,0 +1,2 @@
+このバージョンの主な変更点: パフォーマンスの向上とバグの修正!
+すべての変更履歴はこちら: https://github.com/vector-im/element-android/releases/tag/v1.1.1
diff --git a/fastlane/metadata/android/ja/changelogs/40101020.txt b/fastlane/metadata/android/ja/changelogs/40101020.txt
new file mode 100644
index 0000000000..88e3c79ca8
--- /dev/null
+++ b/fastlane/metadata/android/ja/changelogs/40101020.txt
@@ -0,0 +1,2 @@
+このバージョンの主な変更点: パフォーマンスの向上とバグの修正!
+すべての変更履歴はこちら: https://github.com/vector-im/element-android/releases/tag/v1.1.2
diff --git a/fastlane/metadata/android/ja/changelogs/40101030.txt b/fastlane/metadata/android/ja/changelogs/40101030.txt
new file mode 100644
index 0000000000..87d191b226
--- /dev/null
+++ b/fastlane/metadata/android/ja/changelogs/40101030.txt
@@ -0,0 +1,2 @@
+このバージョンの主な変更点: パフォーマンスの向上とバグの修正!
+すべての変更履歴はこちら: https://github.com/vector-im/element-android/releases/tag/v1.1.3
diff --git a/fastlane/metadata/android/ja/full_description.txt b/fastlane/metadata/android/ja/full_description.txt
new file mode 100644
index 0000000000..855eb309c9
--- /dev/null
+++ b/fastlane/metadata/android/ja/full_description.txt
@@ -0,0 +1,30 @@
+Elementはまったく新しいタイプのメッセンジャーアプリです。
+
+1. あなた自身がプライバシーをコントロールすることを可能にします。
+2. Matrixネットワークにいる誰とでも通信できることはもちろん、Slackなどのアプリとの連携によって他のネットワークとも通信ができます。
+3. 広告、データ収集、バックドア、ユーザーの囲い込みから逃れることができます。
+4. エンドツーエンド暗号化とクロス署名によってあなたを保護します。
+
+Elementは非中央集権型でオープンソースであるため、他のメッセンジャーアプリとは完全に異なっています。
+
+Elementはあなた自身でサーバーをホストすることも、サーバーを選ぶこともできます。これによってあなたのデータと会話に関するプライバシーや所有権はあなた自身で管理できるようになります。さらに、あなたは他のElementユーザーと話せるだけでなくオープンネットワークへのアクセスも可能です。とてもセキュアです。
+
+Elementは、オープンな分散型通信の標準規格であるMatrixで動作するため、これらすべてを実現することができています。
+
+Elementではあなたの会話をどのサーバーでホストするか決めることができます。アプリでは、さまざまな方法で選択できます。
+
+1. matrix.orgの公開サーバーで無料のアカウントを取得します。
+2. あなた自身のハードウェアでサーバーを動かし、アカウントを管理します。
+3. Element Matrix Servicesのホスティングプラットフォームに登録することで、カスタムサーバー上のアカウントを取得できます。
+
+なぜElementを選ぶべきなのか?
+
+データの所有権: 自分でデータやメッセージを保管する場所を決めることができます。あなたが所有権を持ってコントロールすることで、第三者にあなたのデータを渡したり、ビッグデータを収集する巨大テック企業に依存する必要がなくなります。
+
+開かれたネットワークと共同作業: Matrixネットワーク内の他の誰とでも、あるいはElementや他のMatrixアプリを使っているかどうかに関わらず、またSlack、IRC、XMPPのような他のメッセージングシステムを使っているかどうかに関わらず、チャットすることができます。
+
+はるかに安全: 本物のエンドツーエンド暗号化(会話に参加している者のみがメッセージを読める)と会話参加者の真正性を確認するためクロス署名によって。
+
+完全なるコミュニケーションの訪れ: テキスト、音声通話、ビデオ通話、ファイル共有、画面共有、連携機能、ボット、ウィジェットなどのコミュニケーションに必要な機能の全てが実装されています。ルームやコミュニティを立ち上げて連絡を取り合い、物事をスムーズに成し遂げることができます。
+
+いつでもどこでも!: すべてのデバイスとウェブ(https://app.element.io)でメッセージの履歴が完全に同期されるため、どこにいても連絡を取ることができます。
diff --git a/fastlane/metadata/android/ja/short_description.txt b/fastlane/metadata/android/ja/short_description.txt
new file mode 100644
index 0000000000..c3991b7a93
--- /dev/null
+++ b/fastlane/metadata/android/ja/short_description.txt
@@ -0,0 +1 @@
+安全な分散型チャットとVoIP。あなたの情報が第三者から守られます。
diff --git a/fastlane/metadata/android/ja/title.txt b/fastlane/metadata/android/ja/title.txt
new file mode 100644
index 0000000000..376f4a95de
--- /dev/null
+++ b/fastlane/metadata/android/ja/title.txt
@@ -0,0 +1 @@
+Element(エレメントメッセンジャー)
diff --git a/fastlane/metadata/android/nb-NO/changelogs/40100120.txt b/fastlane/metadata/android/nb-NO/changelogs/40100120.txt
new file mode 100644
index 0000000000..163cd64cdc
--- /dev/null
+++ b/fastlane/metadata/android/nb-NO/changelogs/40100120.txt
@@ -0,0 +1,2 @@
+Hovedendringene i denne versjonen: URL-forhåndsvisning, nytt Emoji-tastatur, nye rominnstillingsmuligheter og snø til jul!
+Full endringslogg: https://github.com/vector-im/element-android/releases/tag/v1.0.12
diff --git a/fastlane/metadata/android/nb-NO/changelogs/40100130.txt b/fastlane/metadata/android/nb-NO/changelogs/40100130.txt
new file mode 100644
index 0000000000..23ab42ef2c
--- /dev/null
+++ b/fastlane/metadata/android/nb-NO/changelogs/40100130.txt
@@ -0,0 +1,2 @@
+Hovedendringene i denne versjonen: URL-forhåndsvisning, nytt Emoji-tastatur, nye rominnstillingsmuligheter og snø til jul!
+Full endringslogg: https://github.com/vector-im/element-android/releases/tag/v1.0.13
diff --git a/fastlane/metadata/android/nb-NO/changelogs/40100140.txt b/fastlane/metadata/android/nb-NO/changelogs/40100140.txt
new file mode 100644
index 0000000000..10a3d9b925
--- /dev/null
+++ b/fastlane/metadata/android/nb-NO/changelogs/40100140.txt
@@ -0,0 +1,2 @@
+Hovedendringene i denne versjonen: Rediger romtillatelser, automatisk lys/mørkt tema og en haug med feilrettinger.
+Full endringslogg: https://github.com/vector-im/element-android/releases/tag/v1.0.14
diff --git a/fastlane/metadata/android/nb-NO/changelogs/40100150.txt b/fastlane/metadata/android/nb-NO/changelogs/40100150.txt
new file mode 100644
index 0000000000..3237da115d
--- /dev/null
+++ b/fastlane/metadata/android/nb-NO/changelogs/40100150.txt
@@ -0,0 +1,2 @@
+Hovedendringene i denne versjonen: Sosial innloggingsstøtte.
+Full endringslogg: https://github.com/vector-im/element-android/releases/tag/v1.0.15
diff --git a/fastlane/metadata/android/nb-NO/changelogs/40100160.txt b/fastlane/metadata/android/nb-NO/changelogs/40100160.txt
new file mode 100644
index 0000000000..5502fd3ab1
--- /dev/null
+++ b/fastlane/metadata/android/nb-NO/changelogs/40100160.txt
@@ -0,0 +1,2 @@
+Hovedendringene i denne versjonen: Sosial innloggingsstøtte.
+Full endringslogg: https://github.com/vector-im/element-android/releases/tag/v1.0.15 og https://github.com/vector-im/element-android/releases/tag/v1.0.16
diff --git a/fastlane/metadata/android/nb-NO/changelogs/40100170.txt b/fastlane/metadata/android/nb-NO/changelogs/40100170.txt
new file mode 100644
index 0000000000..f9174a2ee4
--- /dev/null
+++ b/fastlane/metadata/android/nb-NO/changelogs/40100170.txt
@@ -0,0 +1,2 @@
+Hovedendringene i denne versjonen: Feilrettinger!
+Full endringslogg: https://github.com/vector-im/element-android/releases/tag/v1.0.17
diff --git a/fastlane/metadata/android/nb-NO/changelogs/40101000.txt b/fastlane/metadata/android/nb-NO/changelogs/40101000.txt
new file mode 100644
index 0000000000..370dbb36ce
--- /dev/null
+++ b/fastlane/metadata/android/nb-NO/changelogs/40101000.txt
@@ -0,0 +1,2 @@
+Hovedendringene i denne versjonen: forbedring av VoIP (lyd og videosamtaler i DM) og feilrettinger!
+Full endringslogg: https://github.com/vector-im/element-android/releases/tag/v1.1.0
diff --git a/fastlane/metadata/android/nb-NO/changelogs/40101010.txt b/fastlane/metadata/android/nb-NO/changelogs/40101010.txt
new file mode 100644
index 0000000000..c6109b8d9b
--- /dev/null
+++ b/fastlane/metadata/android/nb-NO/changelogs/40101010.txt
@@ -0,0 +1,2 @@
+Hovedendringene i denne versjonen: forbedring av ytelsen og feilrettinger!
+Full endringslogg: https://github.com/vector-im/element-android/releases/tag/v1.1.1
diff --git a/fastlane/metadata/android/nb-NO/changelogs/40101020.txt b/fastlane/metadata/android/nb-NO/changelogs/40101020.txt
new file mode 100644
index 0000000000..9464c6fb0f
--- /dev/null
+++ b/fastlane/metadata/android/nb-NO/changelogs/40101020.txt
@@ -0,0 +1,2 @@
+Hovedendringene i denne versjonen: forbedring av ytelsen og feilrettinger!
+Full endringslogg: https://github.com/vector-im/element-android/releases/tag/v1.1.2
diff --git a/fastlane/metadata/android/nb-NO/changelogs/40101030.txt b/fastlane/metadata/android/nb-NO/changelogs/40101030.txt
new file mode 100644
index 0000000000..1e12246e9a
--- /dev/null
+++ b/fastlane/metadata/android/nb-NO/changelogs/40101030.txt
@@ -0,0 +1,2 @@
+Hovedendringene i denne versjonen: forbedring av ytelsen og feilrettinger!
+Full endringslogg: https://github.com/vector-im/element-android/releases/tag/v1.1.3
diff --git a/fastlane/metadata/android/nb-NO/full_description.txt b/fastlane/metadata/android/nb-NO/full_description.txt
new file mode 100644
index 0000000000..92a3c4c5c3
--- /dev/null
+++ b/fastlane/metadata/android/nb-NO/full_description.txt
@@ -0,0 +1,30 @@
+Element er en ny type messenger og samarbeidsapp som:
+
+1. Gir deg kontrollen for å bevare personvernet ditt
+2. Lar deg kommunisere med hvem som helst i Matrix-nettverket, og til og med ved å integrere med apper som Slack
+3. Beskytter deg mot reklame, datamining og inngjerdede hager
+4. Sikrer deg gjennom end-to-end-kryptering, med kryssignering for å bekrefte andre
+
+Element er helt forskjellig fra andre meldings- og samarbeidsapper fordi det er desentralisert og åpen kildekode.
+
+Element lar deg selv være vert - eller velge en vert - slik at du har personvern, eierskap og kontroll over dataene og samtalene dine. Det gir deg tilgang til et åpent nettverk; slik at du ikke bare holder på å snakke med bare andre Element-brukere. Og det er veldig sikkert.
+
+Element er i stand til å gjøre alt dette fordi det opererer på Matrix - standarden for åpen, desentralisert kommunikasjon.
+
+Element setter deg i kontroll ved å la deg velge hvem som er vert for samtalene dine. Fra Element-appen kan du velge å være vert på forskjellige måter:
+
+1. Få en gratis konto på matrix.org-serveren som er vert for Matrix-utviklerne, eller velg blant tusenvis av offentlige servere som er vert for frivillige
+2. Vær vert for kontoen din ved å kjøre en server på din egen maskinvare
+3. Registrer deg for en konto på en tilpasset server ved å bare abonnere på Hosting Matrix Services-vertsplattformen
+
+ Hvorfor velge Element?
+
+ EGNE DATA DINE : Du bestemmer hvor du vil oppbevare dataene og meldingene dine. Du eier den og kontrollerer den, ikke noe MEGACORP som utvinner dataene dine eller gir tilgang til tredjeparter.
+
+ ÅPEN MELDING OG SAMARBEID : Du kan chatte med alle andre i Matrix-nettverket, enten de bruker Element eller en annen Matrix-app, og selv om de bruker et annet meldingssystem som Slack, IRC eller XMPP.
+
+ SUPER-SECURE : Ekte end-to-end-kryptering (bare de i samtalen kan dekryptere meldinger), og kryssignering for å verifisere enhetene til samtaledeltakerne.
+
+ KOMPLETT KOMMUNIKASJON : Meldinger, tale- og videosamtaler, fildeling, skjermdeling og en hel haug med integrasjoner, bots og widgets. Bygg rom, lokalsamfunn, hold kontakten og få ting gjort.
+
+ ALT DER DU ER : Hold kontakten uansett hvor du er med fullt synkronisert meldingslogg på alle enhetene dine og på nettet på https://app.element.io.
diff --git a/fastlane/metadata/android/nb/changelogs/40100170.txt b/fastlane/metadata/android/nb/changelogs/40100170.txt
new file mode 100644
index 0000000000..3593e50e05
--- /dev/null
+++ b/fastlane/metadata/android/nb/changelogs/40100170.txt
@@ -0,0 +1,2 @@
+Hovedendringene i denne versjonen: Bugfikser!
+Full endringslogg: https://github.com/vector-im/element-android/releases/tag/v1.0.17
diff --git a/fastlane/metadata/android/nb/changelogs/40101010.txt b/fastlane/metadata/android/nb/changelogs/40101010.txt
new file mode 100644
index 0000000000..2d80855ed8
--- /dev/null
+++ b/fastlane/metadata/android/nb/changelogs/40101010.txt
@@ -0,0 +1,2 @@
+Hovedendringene i denne versjonen: Forbedringer i ytelse og bugfikser!
+Full endringslogg: https://github.com/vector-im/element-android/releases/tag/v1.1.1
diff --git a/fastlane/metadata/android/pt-BR/changelogs/40100170.txt b/fastlane/metadata/android/pt-BR/changelogs/40100170.txt
index 15081f160f..2292ddab98 100644
--- a/fastlane/metadata/android/pt-BR/changelogs/40100170.txt
+++ b/fastlane/metadata/android/pt-BR/changelogs/40100170.txt
@@ -1,2 +1,2 @@
-Principais mudanças nessa versão: correções de erros!
-Registro de todas as alterações: https://github.com/vector-im/element-android/releases/tag/v1.0.17
+Principais alterações nesta versão: Correções de bugs!
+Changelog completo: https://github.com/vector-im/element-android/releases/tag/v1.0.17
diff --git a/fastlane/metadata/android/pt-BR/changelogs/40101000.txt b/fastlane/metadata/android/pt-BR/changelogs/40101000.txt
index 8138e376c6..8cdb122f14 100644
--- a/fastlane/metadata/android/pt-BR/changelogs/40101000.txt
+++ b/fastlane/metadata/android/pt-BR/changelogs/40101000.txt
@@ -1,2 +1,2 @@
-Principais mudanças nesta versão: Melhoria de VoIP (chamadas de áudio e vídeo em conversas) e correção de erros!
-Registro de alterações completo: https://github.com/vector-im/element-android/releases/tag/v1.1.0
+Principais alterações nesta versão: melhoramento de VoIP (chamadas de áudio e vídeo em DM) e correções de bugs!
+Changelog completo: https://github.com/vector-im/element-android/releases/tag/v1.1.0
diff --git a/fastlane/metadata/android/pt-BR/changelogs/40101010.txt b/fastlane/metadata/android/pt-BR/changelogs/40101010.txt
index 56f9c2955d..3a1128f229 100644
--- a/fastlane/metadata/android/pt-BR/changelogs/40101010.txt
+++ b/fastlane/metadata/android/pt-BR/changelogs/40101010.txt
@@ -1,2 +1,2 @@
-Principais mudanças nesta versão: melhoria de desempenho e correção de erros!
-Registro de alterações completo: https://github.com/vector-im/element-android/releases/tag/v1.1.1
+Principais alterações nesta versão: melhoramento de performance e correções de bugs!
+Changelog completo: https://github.com/vector-im/element-android/releases/tag/v1.1.1
diff --git a/fastlane/metadata/android/pt-BR/changelogs/40101020.txt b/fastlane/metadata/android/pt-BR/changelogs/40101020.txt
new file mode 100644
index 0000000000..7ee163e003
--- /dev/null
+++ b/fastlane/metadata/android/pt-BR/changelogs/40101020.txt
@@ -0,0 +1,2 @@
+Principais alterações nesta versão: melhoramento de performance e correções de bugs!
+Changelog completo: https://github.com/vector-im/element-android/releases/tag/v1.1.2
diff --git a/fastlane/metadata/android/pt-BR/changelogs/40101030.txt b/fastlane/metadata/android/pt-BR/changelogs/40101030.txt
new file mode 100644
index 0000000000..e83058e014
--- /dev/null
+++ b/fastlane/metadata/android/pt-BR/changelogs/40101030.txt
@@ -0,0 +1,2 @@
+Principais alterações nesta versão: melhoramento de performance e correções de bugs!
+Changelog completo: https://github.com/vector-im/element-android/releases/tag/v1.1.3
diff --git a/fastlane/metadata/android/pt-BR/changelogs/40101040.txt b/fastlane/metadata/android/pt-BR/changelogs/40101040.txt
new file mode 100644
index 0000000000..c58ede0161
--- /dev/null
+++ b/fastlane/metadata/android/pt-BR/changelogs/40101040.txt
@@ -0,0 +1,2 @@
+Principais alterações nesta versão: melhora de performance e correções de bugs!
+Changelog completo: https://github.com/vector-im/element-android/releases/tag/v1.1.4
diff --git a/fastlane/metadata/android/pt-BR/changelogs/40101050.txt b/fastlane/metadata/android/pt-BR/changelogs/40101050.txt
new file mode 100644
index 0000000000..5ab2dbee0d
--- /dev/null
+++ b/fastlane/metadata/android/pt-BR/changelogs/40101050.txt
@@ -0,0 +1,2 @@
+Principais alterações nesta versão: correções quentes para 1.1.4
+Changelog completo: https://github.com/vector-im/element-android/releases/tag/v1.1.5
diff --git a/fastlane/metadata/android/pt-BR/changelogs/40101060.txt b/fastlane/metadata/android/pt-BR/changelogs/40101060.txt
new file mode 100644
index 0000000000..062b53d279
--- /dev/null
+++ b/fastlane/metadata/android/pt-BR/changelogs/40101060.txt
@@ -0,0 +1,2 @@
+Principais alterações nesta versão: correções quentes para 1.1.5
+Changelog completo: https://github.com/vector-im/element-android/releases/tag/v1.1.6
diff --git a/fastlane/metadata/android/pt-BR/full_description.txt b/fastlane/metadata/android/pt-BR/full_description.txt
index 82b38b473c..b4fee53b4d 100644
--- a/fastlane/metadata/android/pt-BR/full_description.txt
+++ b/fastlane/metadata/android/pt-BR/full_description.txt
@@ -1,30 +1,39 @@
-Element é um novo tipo de aplicativo de mensagens e colaboração que:
+Element é tanto um mensageiro seguro como um app de colaboração de time de produtividade que é ideal para chats de grupo enquanto se trabalha remotamente. Este app de chat usa encriptação ponta-a-ponta para prover conferência de vídeo, compartilhamento de arquivo e chamadas de voz poderasos.
-1. Coloca você no controle de sua privacidade;
-2. Permite que você se comunique com qualquer pessoa na rede Matrix e, através de integrações, outros aplicativos como o Slack;
-3. Protege você de anúncios, mineração de dados e de ecossistemas fechados;
-4. Faz uso da criptografia de ponta a ponta, com autoverificação para confirmar outras pessoas.
+As funções de Element incluem:
+- Ferramentas de comunicação online avançadas
+- Mensagens completamente encriptadas para permitir comunicação de corporação mais segura, até para pessoas trabalhando remotamente
+- Chat descentralizado baseado na framework open source Matrix
+- Compartilhamento de arquivo seguramente com dados encriptados enquanto se gerencia projetos
+- Chats de vídeo com Voz sobre IP e compartilhamento de tela
+- Integração fácil com suas ferramentas de colaboração online favoritas, ferramentas de gerenciamento de projetos, serviços de VoIP e outros apps de mensageria de time
-Element é completamente diferente de outros aplicativos de mensagem e colaboração porque é descentralizado e código aberto.
+Element é completamente diferente de outros apps de mensageria e colaboração. Ele opera em Matrix, uma rede aberta para mensageria segura e comunicação descentralizada. Ele permite auto-hospedagem para dar a usuárias(os) máxima propriedade e controle de seus dados e suas mensagens.
-É possível hospedar um servidor ou escolher um servidor hospedeiro, para que você tenha privacidade, controle e que você seja o dono de seus dados e conversas. Com o Element, você possui acesso a uma rede aberta; então você não está preso falando somente com outros usuários no Element. O Element também é muito seguro.
+Privacidade e mensageria encriptada
+Element protege você de ads não-desejados, minagem de dados e jardins murados. Ele também assegura todos os seus dados, vídeo um-a-um e comunicação de voz através de encriptação ponta-a-ponta e verificação de dispositivo assinada cruzado.
-Element é capaz de fazer tudo isso porque ele opera no Matrix, o padrão para comunicação aberta e descentralizada.
+Element dá a você controle sobre sua privacidade enquanto permite a você se comunicar seguramente com qualquer pessoa na rede Matrix, ou outras ferramentas de colaboração ao se integrar com apps tais como Slack.
-Element coloca você no controle ao permitir quem hospeda suas conversas. Neste aplicativo, você pode escolher hospedar de maneiras diferentes:
+Element pode ser auto-hospedado
+Para permitir mais controle de seus dados e conversas sensíveis, Element pode ser auto-hospedado ou você pode escolher qualquer host baseado em Matrix - o standard para comunicação open source e descentralizada. Element dá a você privacidade, conformidade de segurança e flexibilidade de integração.
-1. Crie uma conta gratuita no servidor público matrix.org;
-2. Hospede sua conta no seu servidor;
-3. Entre em uma conta em um servidor customizado ao simplesmente se inscrever na plataforma de hospedagem Serviços Matrix Element.
+Tenha posse de seus dados
+Você decidade onde mannter seus dados e mensagens. Sem o risco de minagem de dados ou acesso de terceiros.
-Por que escolher o Element?
+Element põe você em controle de diferentes maneiras:
+1. Tenha uma conta grátis no servidor público matrix.org hospedado pelos desenvolvedores Matrix, ou escolha de milhares de servidores públicos hospedados por pessoas se voluntariando
+2. Auto-hospede sua conta ao rodar um servidor em sua própria infraestrutura de TI
+3. Registre-se para uma conta num servidor personalizado ao simplesmente assinar a plataforma de hospedagem Element Matrix Services
-SEJA O DONO DE SEUS DADOS: você decide onde manter seus dados e mensagens. Você é o dono deles e também os controla, não alguma mega corporação que minera os seus dados ou compartilha eles com terceiros.
+Mensageria e colaboração abertos
+Você pode fazer chat com qualquer pessoa na rede Matrix, caso ela esteja usando Element, um outro app de Matrix ou mesmo se ela estiver usando um app de mensagem diferente.
-COLABORAÇÃO E MENSAGENS ABERTAS: você pode falar com qualquer outra pessoa na rede Matrix, não importa se ela está usando o Element ou algum outro aplicativo Matrix, ou até mesmo se ela está utilizando um sistema de mensagens diferente como o Slack, IRC ou XMPP.
+Super seguro
+Encriptação ponta-a-ponta real (somente aquelas/es na conversa podem decriptar mensagens), e verificação de dispositivo assinada cuzado.
-SUPER-SEGURO: criptografia de ponta a ponta verdadeira (apenas aqueles na conversa podem descriptografar mensagens), e assinatura cruzada para verificar os dispositivos de participantes de conversas.
+Comunicação e integração completas
+Messageria, chamas de voz e vídeo, compartilhamento de arquivo, compartilhamento de tela e um monte de integrações, bots e widgets. Construa salas, comunidades, fique em contato e tenha as coisas feitas.
-COMUNICAÇÃO COMPLETA: mensagens, chamadas de voz, chamadas de vídeo, compartilhamento de arquivos, compartilhamento de tela e um monte de integrações, robôs e widgets. Construa salas, comunidades, mantenha contato e faça seus projetos.
-
-NÃO IMPORTA ONDE VOCÊ ESTEJA: mantenha contato não importa onde você esteja com o histórico sincronizado de mensagens em todos os seus dispositivos e no navegador em https://app.element.io.
+Continue de onde você parou
+Fique em contato onde quer que você esteja com histórico de mensagem completamente sincronizado por todos os seus dispositivos e na web em https://app.element.io
diff --git a/fastlane/metadata/android/pt-BR/short_description.txt b/fastlane/metadata/android/pt-BR/short_description.txt
index 853f629c30..f03b5347b9 100644
--- a/fastlane/metadata/android/pt-BR/short_description.txt
+++ b/fastlane/metadata/android/pt-BR/short_description.txt
@@ -1 +1 @@
-Conversas e chamadas seguras e descentralizadas. Mantenha seus dados protegidos.
+Mensageiro de grupo - mensagens encriptadas, chat de grupo e chamadas de vídeo
diff --git a/fastlane/metadata/android/pt-BR/title.txt b/fastlane/metadata/android/pt-BR/title.txt
index 5d2ae0c353..90dbcf1bba 100644
--- a/fastlane/metadata/android/pt-BR/title.txt
+++ b/fastlane/metadata/android/pt-BR/title.txt
@@ -1 +1 @@
-Element (o novo Riot.im)
+Element - Mensageiro Seguro
diff --git a/fastlane/metadata/android/ro/short_description.txt b/fastlane/metadata/android/ro/short_description.txt
new file mode 100644
index 0000000000..86abb501b1
--- /dev/null
+++ b/fastlane/metadata/android/ro/short_description.txt
@@ -0,0 +1 @@
+Mesagerie de grup - mesaje criptate, comunicare de grup și apeluri video
diff --git a/fastlane/metadata/android/ro/title.txt b/fastlane/metadata/android/ro/title.txt
new file mode 100644
index 0000000000..09a73b82e2
--- /dev/null
+++ b/fastlane/metadata/android/ro/title.txt
@@ -0,0 +1 @@
+Element - Mesagerie securizată
diff --git a/fastlane/metadata/android/ru/changelogs/40101020.txt b/fastlane/metadata/android/ru/changelogs/40101020.txt
new file mode 100644
index 0000000000..70e164f39d
--- /dev/null
+++ b/fastlane/metadata/android/ru/changelogs/40101020.txt
@@ -0,0 +1,2 @@
+Основные изменения в этой версии: улучшение производительности и исправления ошибок!
+Полный список изменений: https://github.com/vector-im/element-android/releases/tag/v1.1.2
diff --git a/fastlane/metadata/android/ru/changelogs/40101030.txt b/fastlane/metadata/android/ru/changelogs/40101030.txt
new file mode 100644
index 0000000000..381c2761d0
--- /dev/null
+++ b/fastlane/metadata/android/ru/changelogs/40101030.txt
@@ -0,0 +1,2 @@
+Основные изменения в этой версии: улучшение производительности и исправления ошибок!
+Полный список изменений: https://github.com/vector-im/element-android/releases/tag/v1.1.3
diff --git a/fastlane/metadata/android/sv/changelogs/40101020.txt b/fastlane/metadata/android/sv/changelogs/40101020.txt
new file mode 100644
index 0000000000..229793ab31
--- /dev/null
+++ b/fastlane/metadata/android/sv/changelogs/40101020.txt
@@ -0,0 +1,2 @@
+Huvudsakliga ändringar i den här versionen: prestandaförbättringar och buggfixar!
+Full ändringslogg: https://github.com/vector-im/element-android/releases/tag/v1.1.2
diff --git a/fastlane/metadata/android/sv/changelogs/40101030.txt b/fastlane/metadata/android/sv/changelogs/40101030.txt
new file mode 100644
index 0000000000..7e0f8c80d2
--- /dev/null
+++ b/fastlane/metadata/android/sv/changelogs/40101030.txt
@@ -0,0 +1,2 @@
+Huvudsakliga ändringar i den här versionen: prestandaförbättringar och buggfixar!
+Full ändringslogg: https://github.com/vector-im/element-android/releases/tag/v1.1.3
diff --git a/fastlane/metadata/android/sv/changelogs/40101040.txt b/fastlane/metadata/android/sv/changelogs/40101040.txt
new file mode 100644
index 0000000000..46a004ec54
--- /dev/null
+++ b/fastlane/metadata/android/sv/changelogs/40101040.txt
@@ -0,0 +1,2 @@
+Huvudsakliga ändringar i den här versionen: prestandaförbättringar och buggfixar!
+Full ändringslogg: https://github.com/vector-im/element-android/releases/tag/v1.1.4
diff --git a/fastlane/metadata/android/sv/changelogs/40101050.txt b/fastlane/metadata/android/sv/changelogs/40101050.txt
new file mode 100644
index 0000000000..158e2032b7
--- /dev/null
+++ b/fastlane/metadata/android/sv/changelogs/40101050.txt
@@ -0,0 +1,2 @@
+Huvudsakliga ändringar i den här versionen: hotfixar för 1.1.4
+Full ändringslogg: https://github.com/vector-im/element-android/releases/tag/v1.1.5
diff --git a/fastlane/metadata/android/sv/changelogs/40101060.txt b/fastlane/metadata/android/sv/changelogs/40101060.txt
new file mode 100644
index 0000000000..cc7a9b84b6
--- /dev/null
+++ b/fastlane/metadata/android/sv/changelogs/40101060.txt
@@ -0,0 +1,2 @@
+Huvudsakliga ändringar i den här versionen: hotfixar för 1.1.5
+Full ändringslogg: https://github.com/vector-im/element-android/releases/tag/v1.1.6
diff --git a/fastlane/metadata/android/sv/changelogs/40101070.txt b/fastlane/metadata/android/sv/changelogs/40101070.txt
new file mode 100644
index 0000000000..4756a2d028
--- /dev/null
+++ b/fastlane/metadata/android/sv/changelogs/40101070.txt
@@ -0,0 +1,2 @@
+Huvudsakliga ändringar i den här versionen: betastöd för utrymmen. Komprimera video innan den skickas.
+Full ändringslogg: https://github.com/vector-im/element-android/releases/tag/v1.1.7
diff --git a/fastlane/metadata/android/sv/full_description.txt b/fastlane/metadata/android/sv/full_description.txt
index d130e9214a..5302976ed7 100644
--- a/fastlane/metadata/android/sv/full_description.txt
+++ b/fastlane/metadata/android/sv/full_description.txt
@@ -1,30 +1,39 @@
-Element är en ny sorts meddelande- och samarbetsapp som:
+Element är både en säker meddelandeapp och en samarbetsapp för produktivitet som är ideal för gruppchattar vid distansarbete. Appen använder totalsträckskryptering för att tillhandahålla kraftfulla videogruppsamtal, fildelning och röstsamtal.
-1. Sätter dig i kontroll för att kunna säkerställa ditt privatliv
-2. Låter dig kommunicera med vem som helst i Matrix-nätverket, och till och med bortom det genom integrationer med appar som Slack
-3. Skyddar dig från reklam, datainsamling och inlåsning
-4. Säkrar dig genom totalsträckskryptering, med korssingering för att verifiera andra
+Elements funktioner inkluderar:
+- Avancerade kommunikationsverktyg
+- Fullt krypterade meddelanden för att tillåta säkrare företagskommunikation, även för distansarbetare
+- Decentraliserad chatt baserad på det öppna ramverket Matrix
+- Säker fildelning med krypterad data vid hantering av projekt
+- Videochattar med Voice over IP och skärmdelning
+- Enkel integration med dina föredragna onlinesamarbetsverktyg, projektledningsverktyg, VoIP-tjänster och andra teammeddelandeappar
-Element skiljer sig helt från andra meddelande- och samarbetsappar genom att vara decentraliserad och öppen källkod.
+Element är helt olik andra meddelande- och samarbetsappar. Den använder Matrix, ett öppet nätverk för säkra meddelanden och decentraliserad kommunikation. Den låter dig driva en igen server för att ge användare maximalt ägandeskap över sin data och sina meddelanden.
-Element låter dig driva en egen server - eller välja en värd - så att du har sekretess, ägande och kontroll över din data och dina konversationer. Den ger dig tillgång till ett öppet nätverk; så att du inte kan prata bara med Element-användare. Och den är väldigt säker.
+Sekretess och krypterade meddelanden
+Element skyddar dig från oönskad reklam, datainsamling och inlåsning. Den skyddar även all din data, en-till-en-video- och röstkommunikation genom totalsträckskryptering och korssignerad enhetsverifiering.
-Element kan göra allt detta för att den använder Matrix - standarden för öppen decentraliserad kommunikation.
+Element sätter dig i kontroll över ditt privatliv och låter dig kommunicera säkert med vem som helst i Matrix-nätverket, eller andra samarbetsverktyg genom att integrera med appar som Slack.
-Element sätter dig i kontroll genom att låta dig välja att vara värd för dina konversationer. Från appen Element kan du välja att ansluta på följande sätt:
+Du kan driva Element själv
+För att tillåta större kontroll över din känsliga data och konversationer, så kan du lägga Element på en egen server eller använda valfri Matrix-baserad värd - standarden för open source-baserad, decentraliserad kommunikation. Element ger dig sekretess, säkerhetsefterlevnad och integrationsflexibilitet.
-1. Skaffa ett gratis konto på den publika servern på matrix.org, vilken drivs av Matrix-utvecklarna, eller välj bland tusentals offentliga servrar som drivs av volontärer
-2. Var värd för ditt eget konto genom att driva en server på din egen hårdvara
-3. Skapa ett konto på en anpassad server genom att registrera dig på värdplattformen Element Matrix Services
+Äg din data
+Du bestämmer vart du vill lagra din data och dina meddelanden, utan rist för datainsamling eller åtkomst av tredje parter.
-Varför välja Element?
+Element sätter dig i kontroll på olika sätt:
+1. Få ett gratiskonto på den offentliga servern matrix.org som drivas av Matrixutvecklarna, eller välj bland tusentals offentliga servrar som drivs av volontärer
+2. Självdriv ditt konto genom att driva en server på din egen IT-infrastruktur
+3. Skapa ett konto på en anpassad server genom att abonnera på värdplattformen Element Matrix Services
-ÄG DIN DATA: Du väljer var du vill ha din data och dina meddelanden. Du äger den och kontrollerar den, inte nåt stort företag som samlar in din data och ger den till tredje parter.
+Öppen meddelandehantering och kommunikation
+Du kan chatta med vem som helst i Matrix-nätverket, oavsett om de använder Matrix, en annan Matrix-app eller till och med en annan meddelandeapp.
-ÖPPEN KOMMUNIKATION OCH ÖPPET SAMARBETE: Du kan chatta med vem som helst på Matrix-nätverket, oavsett om de använder Element eller en annan Matrix-app, och till och med om de använder ett annat meddelandesystem som Slack, IRC eller XMPP.
+Supersäker
+Riktig totalsträckskryptering (bara de i konversationen kan avkryptera meddelanden), och korssignerad enhetsverifiering.
-SUPERSÄKER: Riktig totalsträckskryptering (bara de in konversationen kan avkryptera meddelandena), och korssingering för att verifiera konversationsmedlemmars enheter.
+Komplett kommunikation och integration
+Meddelanden, röst- och videosamtal, fildelning, skärmdelning och massa integrationer, bottar och widgets. Bygg rum och gemenskaper, håll kontakten och få saker gjorda.
-KOMPLETT KOMMUNIKATION: Meddelanden, röst- och videosamtal, fildelning, skärmdelning och massa integrationer, bottar och widgets. Skapa rum och gemenskaper, håll kontakten och få saker gjorda.
-
-ÖVERALLT DÄR DU ÄR: Håll kontakten vart du än befinner dig med fullständigt synkroniserad meddelandehistorik på alla dina enheter och på webben på https://app.element.io.
+Fortsätt där du lämnade
+Håll kontakten vart du än är med fullt synkroniserad meddelandehistorik på alla dina enheter och på webben på https://app.element.io
diff --git a/fastlane/metadata/android/sv/short_description.txt b/fastlane/metadata/android/sv/short_description.txt
index ddfc5dcbfb..c16da5c761 100644
--- a/fastlane/metadata/android/sv/short_description.txt
+++ b/fastlane/metadata/android/sv/short_description.txt
@@ -1 +1 @@
-Säker decentraliserad chatt och VoIP. Håll din data säker från tredje parter.
+Gruppmeddelandeapp - krypterade meddelanden, gruppchatt och videosamtal
diff --git a/fastlane/metadata/android/sv/title.txt b/fastlane/metadata/android/sv/title.txt
index 573e27fab9..4fc189de15 100644
--- a/fastlane/metadata/android/sv/title.txt
+++ b/fastlane/metadata/android/sv/title.txt
@@ -1 +1 @@
-Element (före detta Riot.im)
+Element - Säker meddelandeapp
diff --git a/fastlane/metadata/android/uk/changelogs/40101020.txt b/fastlane/metadata/android/uk/changelogs/40101020.txt
new file mode 100644
index 0000000000..469de21a6f
--- /dev/null
+++ b/fastlane/metadata/android/uk/changelogs/40101020.txt
@@ -0,0 +1,2 @@
+Основні зміни в цій версії: поліпшення продуктивності та виправлення помилок!
+Повний журнал змін: https://github.com/vector-im/element-android/releases/tag/v1.1.2
diff --git a/fastlane/metadata/android/uk/changelogs/40101030.txt b/fastlane/metadata/android/uk/changelogs/40101030.txt
new file mode 100644
index 0000000000..da2bb0ddd6
--- /dev/null
+++ b/fastlane/metadata/android/uk/changelogs/40101030.txt
@@ -0,0 +1,2 @@
+Основні зміни в цій версії: поліпшення продуктивності та виправлення помилок!
+Повний журнал змін: https://github.com/vector-im/element-android/releases/tag/v1.1.3
diff --git a/fastlane/metadata/android/uk/changelogs/40101040.txt b/fastlane/metadata/android/uk/changelogs/40101040.txt
new file mode 100644
index 0000000000..663133a99c
--- /dev/null
+++ b/fastlane/metadata/android/uk/changelogs/40101040.txt
@@ -0,0 +1,2 @@
+Основні зміни в цій версії: поліпшення швидкодії та виправлення помилок!
+Повний журнал змін: https://github.com/vector-im/element-android/releases/tag/v1.1.4
diff --git a/fastlane/metadata/android/uk/changelogs/40101050.txt b/fastlane/metadata/android/uk/changelogs/40101050.txt
new file mode 100644
index 0000000000..00f44f2606
--- /dev/null
+++ b/fastlane/metadata/android/uk/changelogs/40101050.txt
@@ -0,0 +1,2 @@
+Основні зміни в цій версії: виправлення для 1.1.4
+Повний журнал змін: https://github.com/vector-im/element-android/releases/tag/v1.1.5
diff --git a/fastlane/metadata/android/uk/changelogs/40101060.txt b/fastlane/metadata/android/uk/changelogs/40101060.txt
new file mode 100644
index 0000000000..8a4ae2a4d2
--- /dev/null
+++ b/fastlane/metadata/android/uk/changelogs/40101060.txt
@@ -0,0 +1,2 @@
+Основні зміни в цій версії: виправлення для 1.1.5
+Повний журнал змін: https://github.com/vector-im/element-android/releases/tag/v1.1.6
diff --git a/fastlane/metadata/android/uk/changelogs/40101070.txt b/fastlane/metadata/android/uk/changelogs/40101070.txt
new file mode 100644
index 0000000000..4d60bb1704
--- /dev/null
+++ b/fastlane/metadata/android/uk/changelogs/40101070.txt
@@ -0,0 +1,2 @@
+Основні зміни в цій версії: бета-підтримка Spaces. Стиснення відео перед надсиланням.
+Повний журнал змін: https://github.com/vector-im/element-android/releases/tag/v1.1.7
diff --git a/fastlane/metadata/android/uk/full_description.txt b/fastlane/metadata/android/uk/full_description.txt
index 026ae4162a..df06315754 100644
--- a/fastlane/metadata/android/uk/full_description.txt
+++ b/fastlane/metadata/android/uk/full_description.txt
@@ -1,30 +1,39 @@
-Element — це застосунок для спілкування та співпраці нового типу, який:
+Element — це і безпечний месенджер, і застосунок для співпраці команди, який ідеально підходить для групових бесід під час віддаленої роботи. Цей застосунок для спілкування застосовує наскрізне шифрування для забезпечення відеоконференцій, обміну файлами та голосових викликів.
-1. Надає вам повний контроль за своєю конфіденційністю
-2. Дозволяє спілкування з будь-ким у мережі Matrix та поза нею, інтегруючись із такими застосунками, як Slack
-3. Убезпечує вас від реклами, збору даних та штучних обмежень
-4. Захищає ваше спілкування наскрізним шифруванням із перехресним підписуванням для звірення інших осіб
+Можливості Element включають:
+- Розширені засоби спілкування в Інтернеті
+- Повністю зашифровані повідомлення для надання можливості безпечнішого корпоративного спілкування, навіть для віддалених працівників
+- Децентралізований чат на основі відкритого коду Matrix
+- Безпечний обмін файлами із зашифрованими даними для керування проєктами
+- Відеочати з передачею голосу через IP та показом екрану іншим
+- Проста інтеграція з вашими улюбленими інструментами для онлайн-співпраці, інструментами керування проєктами, послугами VoIP та іншими застосунками обміну повідомленнями для команд
-Element ґрунтовно відрізняється від інших застосунків для спілкування та співпраці тому що він є децентралізованим та відкритоджерельним.
+Element цілковито відрізняється від інших застосунків обміну повідомленнями та спільної роботи. Він працює на Matrix, відкритій мережі для безпечного обміну повідомленнями та децентралізованого зв'язку. Це дозволяє самостійне розгортання, щоб надати користувачам якнайбільше володіння та контролю над їх даними та повідомленнями.
-Element дозволяє вам розміщувати сервер в себе або обирати будь-якого з надавачів послуг, таким чином забезпечуючи вам конфіденційність і можливість володіти власними даними й бесідами та контролювати їх. Він надає вам доступ до відкритої мережі, тож ви не є обмеженими спілкуванням виключно з користувачами Element. І він є дуже надійним та безпечним.
+Приватність та обмін зашифрованими повідомленнями
+Element захищає вас від небажаної реклами, збору даних та обмежень. Він також захищає всі ваші дані, відео та голосовий зв'язок віч-на-віч за допомогою наскрізного шифрування та взаємного підписування пристроїв.
-Element здатен забезпечити усе це завдяки тому, що він заснований на протоколі Matrix — стандарті для відкритого та децентралізованого спілкування.
+Element дає вам можливість контролювати вашу приватність, одночасно дозволяючи вам безпечно спілкуватися з будь-ким у мережі Matrix або через інші інструменти ділової співпраці, інтегрувавшись із такими програмами, як Slack.
-Element надає вам повний контроль, дозволяючи обирати з-поміж надавачів послуг, що обслуговують сервери з вашими бесідами. Ви вільні обрати будь-який спосіб розміщення прямо з застосунку Element:
+Element можна розгортати самостійно
+Щоб забезпечити більше контролю над вашими приватними даними та розмовами, Element можна самостійно розміщувати або ви можете вибрати будь-який вузол на основі Matrix — стандарт для децентралізованого спілкування з відкритим кодом. Element надає вам приватність, відповідність безпеці та гнучкість інтеграції.
-1. Отримати безкоштовний обліковий запис на загальнодоступному сервері matrix.org, який обслуговують розробники Matrix, чи на одному з тисяч публічних серверів, які обслуговують волонтери
-2. Розмістити свій обліковий запис на власному сервері
-3. Зареєструватись на індивідуальному сервері, просто підписавшись на послуги платформи Element Matrix Services
+Ваші дані
+Ви вирішуєте, де зберігати свої дані та повідомлення. Без ризику видобутку даних або стороннього доступу.
-Чому я маю обрати Element?
+Element надає такі можливості на вибір:
+1. Отримайте безплатний обліковий запис на загальнодоступному сервері matrix.org, розміщеному розробниками Matrix, або виберіть серед тисяч загальнодоступних серверів, розміщених волонтерами
+2. Самостійно розмістіть свій обліковий запис, запустивши сервер на власній ІТ-інфраструктурі
+3. Зареєструйте обліковий запис на власному сервері, просто підписавшись на хостинг-платформу Element Matrix Services
-ВОЛОДІЙТЕ ВАШИМИ ДАНИМИ: Ви вирішуєте де тримати ваші дані та повідомлення. Саме ви володієте ними та контролюєте їх, а не якась Мегакорпорація, що збирає ваші дані та надає стороннім особам доступ до них.
+Відкриті обмін повідомленнями та співпраця
+Ви можете спілкуватися з усіма у мережі Matrix, незалежно від того, чи користуються вони Element, іншим застосунком Matrix або навіть якщо іншим застосунком для обміну повідомленнями.
-ВІДКРИТІ ОБМІН ПОВІДОМЛЕННЯМИ ТА СПІВПРАЦЯ: Ви можете балакати з будь-ким у мережі Matrix, хоч вони користуються Element, хоч іншим застосунком для Matrix, і навіть якщо вони користуються іншою системою обміну повідомленнями на кшталт Slack, IRC чи XMPP.
+Надбезпечний
+Справжнє наскрізне шифрування (лише учасники бесіди можуть розшифровувати повідомлення) та взаємне підписування пристроїв.
-НАДБЕЗПЕЧНІСТЬ: Справжнє наскрізне шифрування (лише ваші співрозмовники здатні дешифровувати повідомлення) та перехресне підписування для звірення пристроїв інших учасників бесіди.
+Повноцінні спілкування та інтеграція
+Обмін повідомленнями, голосові та відеовиклики, обмін файлами, спільний доступ до екрана та ціла купа інтеграцій, ботів та віджетів. Створюйте кімнати, спільноти, залишайтеся на зв’язку та виконуйте завдання.
-ДОВЕРШЕНИЙ ЗВʼЯЗОК: Повідомлення, голосові та відеодзвінки, обмін файлами, розподіл екрану та ціла купа інтеграцій, ботів та знадобів. Створюйте кімнати й спільноти, залишайтесь на зв'язку та завершуйте свої справи.
-
-ДЕ Б ВИ НЕ БУЛИ: Залишайтесь на зв'язку де б ви не були, разом з синхронізовною історією листувань на усіх ваших пристроях та в Інтернеті на https://app.element.io.
+Продовжуйте, де зупинилися
+Залишайтеся на зв'язку, де б ви не знаходились, з повністю синхронізованою історією повідомлень на всіх своїх пристроях та в Інтернеті за адресою https://app.element.io
diff --git a/fastlane/metadata/android/uk/short_description.txt b/fastlane/metadata/android/uk/short_description.txt
index 116f6f95b7..fa42cce81e 100644
--- a/fastlane/metadata/android/uk/short_description.txt
+++ b/fastlane/metadata/android/uk/short_description.txt
@@ -1 +1 @@
-Захищене децентралізоване листування та дзвінки. Тримайте ваші дані в безпеці.
+Груповий месенджер — зашифровані повідомлення, групові бесіди та відеовиклики
diff --git a/fastlane/metadata/android/uk/title.txt b/fastlane/metadata/android/uk/title.txt
index 88e3f7c573..0a170676ff 100644
--- a/fastlane/metadata/android/uk/title.txt
+++ b/fastlane/metadata/android/uk/title.txt
@@ -1 +1 @@
-Element (раніше Riot.im)
+Element — Безпечний месенджер
diff --git a/fastlane/metadata/android/vi/short_description.txt b/fastlane/metadata/android/vi/short_description.txt
index b41ac0ce82..cead47480f 100644
--- a/fastlane/metadata/android/vi/short_description.txt
+++ b/fastlane/metadata/android/vi/short_description.txt
@@ -1 +1 @@
-Ứng dụng chat và gọi phân tán bảo mật. Bảo vệ dữ liệu của bạn khỏi bên thứ ba.
+Nhắn tin nhóm - tin nhắn được mã hoá, cuộc trò chuyện nhóm và cuộc gọi video
diff --git a/fastlane/metadata/android/vi/title.txt b/fastlane/metadata/android/vi/title.txt
index 2a3bef31df..8ef5498c44 100644
--- a/fastlane/metadata/android/vi/title.txt
+++ b/fastlane/metadata/android/vi/title.txt
@@ -1 +1 @@
-Element (trước là Riot.im)
+Element - Nhắn tin bảo mật
diff --git a/fastlane/metadata/android/zh-Hans/changelogs/40101020.txt b/fastlane/metadata/android/zh-Hans/changelogs/40101020.txt
new file mode 100644
index 0000000000..0de3f2aed0
--- /dev/null
+++ b/fastlane/metadata/android/zh-Hans/changelogs/40101020.txt
@@ -0,0 +1,2 @@
+此版本中的主要更新:改进性能和错误修复!
+完整的更新记录:https://github.com/vector-im/element-android/releases/tag/v1.1.2
diff --git a/fastlane/metadata/android/zh-Hans/changelogs/40101030.txt b/fastlane/metadata/android/zh-Hans/changelogs/40101030.txt
new file mode 100644
index 0000000000..5a7fae92d5
--- /dev/null
+++ b/fastlane/metadata/android/zh-Hans/changelogs/40101030.txt
@@ -0,0 +1,2 @@
+此版本中的主要更新:改进性能和修复错误!
+完整的更新记录:https://github.com/vector-im/element-android/releases/tag/v1.1.3
diff --git a/fastlane/metadata/android/zh-Hans/changelogs/40101040.txt b/fastlane/metadata/android/zh-Hans/changelogs/40101040.txt
new file mode 100644
index 0000000000..44a3547b3e
--- /dev/null
+++ b/fastlane/metadata/android/zh-Hans/changelogs/40101040.txt
@@ -0,0 +1,2 @@
+此版本中的主要更新:改进性能和修复错误!
+完整的更新记录:https://github.com/vector-im/element-android/releases/tag/v1.1.4
diff --git a/fastlane/metadata/android/zh-Hans/changelogs/40101050.txt b/fastlane/metadata/android/zh-Hans/changelogs/40101050.txt
new file mode 100644
index 0000000000..c320815a00
--- /dev/null
+++ b/fastlane/metadata/android/zh-Hans/changelogs/40101050.txt
@@ -0,0 +1,2 @@
+此版本中的主要更新:1.1.4 的热修复
+完整的更新记录:https://github.com/vector-im/element-android/releases/tag/v1.1.5
diff --git a/fastlane/metadata/android/zh-Hans/changelogs/40101060.txt b/fastlane/metadata/android/zh-Hans/changelogs/40101060.txt
new file mode 100644
index 0000000000..193ef8f48e
--- /dev/null
+++ b/fastlane/metadata/android/zh-Hans/changelogs/40101060.txt
@@ -0,0 +1,2 @@
+此版本中的主要更新:1.1.5 的热修复
+完整的更新记录:https://github.com/vector-im/element-android/releases/tag/v1.1.6
diff --git a/fastlane/metadata/android/zh-Hans/changelogs/40101070.txt b/fastlane/metadata/android/zh-Hans/changelogs/40101070.txt
new file mode 100644
index 0000000000..ba8e92be9b
--- /dev/null
+++ b/fastlane/metadata/android/zh-Hans/changelogs/40101070.txt
@@ -0,0 +1,2 @@
+此版本中的主要更新:对「空间」的测试版支持。发送前压缩视频。
+完整的更新记录:https://github.com/vector-im/element-android/releases/tag/v1.1.7
diff --git a/fastlane/metadata/android/zh-Hans/full_description.txt b/fastlane/metadata/android/zh-Hans/full_description.txt
index 4791c9652b..fa6b00f1e4 100644
--- a/fastlane/metadata/android/zh-Hans/full_description.txt
+++ b/fastlane/metadata/android/zh-Hans/full_description.txt
@@ -1,30 +1,39 @@
-Element 是一种新型的通讯与协作应用:
+Element 不仅是安全的通讯软件,同时也是生产力团队协作应用,非常适合在远端工作时进行群组聊天。此聊天应用使用了端到端加密来提供强大的视频会议、文件分享与语音通话功能。
-1. 使您可以掌控您的隐私
-2. 使您与 Matrix 网络中的任何人交流,甚至可以通过集成功能与如 Slack 之类的其他应用通讯
-3. 保护您免受广告,大数据挖掘和封闭服务的侵害
-4. 通过端到端加密保证安全,通过交叉签名验证其他人
+Element 的功能包含了:
+- 进阶的线上通讯工具
+- 完全加密的信息,即使对于远端工作者来说,也可以有更安全的公司通讯
+- 以 Matrix 开放源码框架为基础的去中心化的聊天
+- 在管理项目时通过加密资料安全地分享文件
+- 包含了 VoIP 与画面分享的视频聊天
+- 与你最喜欢的协作工具、项目管理工具、VoIP 服务与其他团队信息应用轻松整合
-Element 与其他通讯与协作应用完全不同,因为它是去中心化且开源的。
+Element 与其他信息传递与协作应用完全不同。它在 Matrix(一个用于安全传递讯息与去中心化通讯的开放网络)上运行。其可以自建,让使用者对他们的资料和信息拥有最大的所有权与控制权。
-Element 允许您自托管——或者选择托管商——因此,您能拥有数据和会话的隐私权,所有权和控制权。它允许您访问开放网络;因此,您可以与 Element 用户以外的人交流。并且它非常安全。
+隐私与加密信息传递
+Element 保护你不受不想要的广告、信息泄露与围城侵扰。其也通过端到端加密与交叉签章装置验证保护了你所有的资料,并提供一对一视频以及语音通讯。
-Element 之所以可以做到这些,是因为它在 Matrix 上运行——开放,去中心化通讯的标准。
+Element 通过与其他商业协作工具,如 Slack 等应用整合,让你可以在控制你的隐私的同时,也可以与 Matrix 网络上的任何人安全地通讯。
-通过让您选择由谁来托管您的会话,Element 让您掌控一切。在 Element 应用中,您可以选择不同的托管方式:
+Element 可以自建
+为了可以完整控制你的敏感资料与对话,Element 可以自建,你也可以选择任何以 Matrix 为基础的服务提供商,开放源码、去中心化的通讯标准。Element 为你提供隐私、安全合规与整合灵活性。
-1. 在由 Matrix 开发者托管的 matrix.org 公共服务器上获取免费帐户,或从志愿者托管的上千个公共服务器中选择
-2. 在您自己的硬件上运行服务器,自托管您的会话
-3. 通过订阅 Element Matrix Services 托管平台,简单地在自定义服务器上注册账户
+拥有你的资料
+你可以决定将你的资料与信息储存在何处。没有信息泄露或被第三方爬取的风险。
-为什么选择 Element?
+Element 透过不同的方式让你掌控一切:
+1. 在 Matrix 开发者架设的 matrix.org 公开服务器上取得免费帐号,或是从数千个由志愿者架设的公开服务器中选择
+2. 在你自己的 IT 基础架构上的服务器自行托管你的帐号
+3. 只要订阅 Element Matrix Services 托管平台就可以在自定义的服务器上注册帐号
-掌控您的数据:您来决定存放您的数据和消息的位置。拥有并控制它的是您,而不是挖掘您的数据或与第三方分享的巨型企业。
+开放信息传递与协作
+你可以与 Matrix 网络上的任何人聊天,不论他们是使用 Element、其他 Matrix 应用或其他通讯应用。
-开放通讯与协作:您可以与 Matrix 网络中的任何人聊天,不论他们使用 Element 还是其他 Matrix 应用,甚至/即使他们在使用不同的通讯系统,例如 Slack,IRC 或 XMPP。
+超级安全
+真正的端到端加密(仅有那些在对话中的可以解密讯息)以及交叉签章装置验证。
-超级安全:支持真正的端到端加密(仅有会话中的人可以解密消息),还有能够验证会话参与方的设备的交叉签名。
+完整的通讯与整合
+信息传递、语音与视频通话、文件分享、画面分享与超多的整合、机器人与挂件。建构聊天室、社群、保持联络并完成工作。
-完善的通讯方式:消息,语音和视频通话,文件共享,屏幕共享和大量集成功能,机器人和小挂件。建立房间与社区,保持联系并完成工作。
-
-随时随地:消息历史可在您的全部设备和 https://app.element.io 网页端之间完全同步,无论您在哪里,都可以保持联系。
+从上次离开的地方开始
+无论你身在何处,都可以透过在你所有设备与网页 https://app.element.io 间完全同步的信息历史保持联络
diff --git a/fastlane/metadata/android/zh-Hans/short_description.txt b/fastlane/metadata/android/zh-Hans/short_description.txt
index 53d7d33403..e271e7f9a4 100644
--- a/fastlane/metadata/android/zh-Hans/short_description.txt
+++ b/fastlane/metadata/android/zh-Hans/short_description.txt
@@ -1 +1 @@
-安全、去中心化的聊天与 VoIP 通话。保护您的数据不被第三方窃取。
+群组消息应用-加密的消息传递、群组聊天和视频通话
diff --git a/fastlane/metadata/android/zh-Hans/title.txt b/fastlane/metadata/android/zh-Hans/title.txt
index 03aecdd2cb..aad1a96f19 100644
--- a/fastlane/metadata/android/zh-Hans/title.txt
+++ b/fastlane/metadata/android/zh-Hans/title.txt
@@ -1 +1 @@
-Element(曾为 Riot.im)
+Element - 安全消息应用
diff --git a/fastlane/metadata/android/zh-Hant/changelogs/40101020.txt b/fastlane/metadata/android/zh-Hant/changelogs/40101020.txt
new file mode 100644
index 0000000000..90e76b074e
--- /dev/null
+++ b/fastlane/metadata/android/zh-Hant/changelogs/40101020.txt
@@ -0,0 +1,2 @@
+此版本中的主要變更:效能改進與錯誤修復!
+完整變更紀錄:https://github.com/vector-im/element-android/releases/tag/v1.1.2
diff --git a/fastlane/metadata/android/zh-Hant/changelogs/40101030.txt b/fastlane/metadata/android/zh-Hant/changelogs/40101030.txt
new file mode 100644
index 0000000000..c13d6ecfd4
--- /dev/null
+++ b/fastlane/metadata/android/zh-Hant/changelogs/40101030.txt
@@ -0,0 +1,2 @@
+此版本中的主要變更:效能改進與錯誤修復!
+完整變更紀錄:https://github.com/vector-im/element-android/releases/tag/v1.1.3
diff --git a/fastlane/metadata/android/zh-Hant/changelogs/40101040.txt b/fastlane/metadata/android/zh-Hant/changelogs/40101040.txt
new file mode 100644
index 0000000000..1786691c42
--- /dev/null
+++ b/fastlane/metadata/android/zh-Hant/changelogs/40101040.txt
@@ -0,0 +1,2 @@
+此版本中的主要變動:效能改善與錯誤修復!
+完整的變更紀錄:https://github.com/vector-im/element-android/releases/tag/v1.1.4
diff --git a/fastlane/metadata/android/zh-Hant/changelogs/40101050.txt b/fastlane/metadata/android/zh-Hant/changelogs/40101050.txt
new file mode 100644
index 0000000000..899ce72c9a
--- /dev/null
+++ b/fastlane/metadata/android/zh-Hant/changelogs/40101050.txt
@@ -0,0 +1,2 @@
+此版本中的主要變動:1.1.4 的快速修補
+完整的變更紀錄:https://github.com/vector-im/element-android/releases/tag/v1.1.5
diff --git a/fastlane/metadata/android/zh-Hant/changelogs/40101060.txt b/fastlane/metadata/android/zh-Hant/changelogs/40101060.txt
new file mode 100644
index 0000000000..838dc6d731
--- /dev/null
+++ b/fastlane/metadata/android/zh-Hant/changelogs/40101060.txt
@@ -0,0 +1,2 @@
+此版本中的主要變動:1.1.5 的快速修補
+完整的變更紀錄:https://github.com/vector-im/element-android/releases/tag/v1.1.6
diff --git a/fastlane/metadata/android/zh-Hant/changelogs/40101070.txt b/fastlane/metadata/android/zh-Hant/changelogs/40101070.txt
new file mode 100644
index 0000000000..c62c7d5224
--- /dev/null
+++ b/fastlane/metadata/android/zh-Hant/changelogs/40101070.txt
@@ -0,0 +1,2 @@
+此版本中的主要變動:對「空間」的測試版支援。傳送前壓縮影片。
+完整的變更紀錄:https://github.com/vector-im/element-android/releases/tag/v1.1.7
diff --git a/fastlane/metadata/android/zh-Hant/full_description.txt b/fastlane/metadata/android/zh-Hant/full_description.txt
index 2fdf6fa478..90c0eb4c4c 100644
--- a/fastlane/metadata/android/zh-Hant/full_description.txt
+++ b/fastlane/metadata/android/zh-Hant/full_description.txt
@@ -1,30 +1,39 @@
-Element 是一種新型態的即時通訊軟體與協作應用程式:
+Element 同時是安全的通訊軟體,也是生產力團隊協作應用程式,非常適合在遠端工作時進行群組聊天。此聊天應用程式使用了端到端加密來提供強大的視訊會議、檔案分享與語音通話。
-1. 自己的隱私自己掌控
-2. 讓您與任何在 Matrix 網路中的人通訊,甚至可與如 Slack 等的應用程式整合
-3. 保護您免受廣告、資料採礦與圍牆花園的侵害
-4. 透過端到端加密保護您,並使用交叉簽章來驗證其他人
+Element 的功能包含了:
+- 進階線上通訊工具
+- 完全加密的訊息,即使對於遠端工作者,也可以有更安全的公司通訊
+- 以 Matrix 開放原始碼框架為基礎的去中心化的聊天
+- 在管理專案時透過加密資料安全地分享檔案
+- 包含了 VoIP 與畫面分享的視訊聊天
+- 與您最喜歡的協作工具、專案管理工具、VoIP 服務與其他團隊訊息應用程式輕鬆整合
-Element 是去中心化且開放原始碼的應用程式,因此與其他即時通訊與協作軟體完全不同。
+Element 與其他訊息傳遞與協作應用程式完全不同。它在 Matrix(一個用於安全傳遞訊息與去中心化通訊的開放網路)上執行。其可以自架,讓使用者對他們的資料與訊息有最大的所有權與控制權。
-Element 讓您可以自架(或是自行選擇服務提供者)所以您擁有您資料與對話的隱私、所有權與控制權。它讓您可以存取開放的網路;因此,您不僅可以與其他 Matrix 使用者聊天。而且非常安全。
+隱私與加密訊息傳遞
+Element 保護您不受不想要的廣告、資料挖礦與圍牆花園侵擾。其也透過端到端加密與交叉簽章裝置驗證保護了您所有的資料,並提供一對一視訊以及語音通訊。
-Element 能作到這些事情是因為它在 Matrix 上執行,這是一個開放的去中心化通訊的標準。
+Element 透過與其他商業協作工具,如 Slack 等應用程式整合,讓您可以在控制您的隱私的同時,也可以與 Matrix 網路上的任何人安全地通訊。
-Element 讓您選擇您要在哪裡託管您的對話來將控制權還給您。在 Element 應用程式中,您可以選擇其他方式來託管:
+Element 可以自架
+為了可以完整控制您的敏感資料與對話,Element 可以自架,您也可以選擇任何以 Matrix 為基礎的服務提供商,開放原始碼、去中心化的通訊標準。Element 為您提供隱私、安全合規與整合活性。
-1. 在由 Matrix 開發者架設的 matrix.org 公開伺服器上取得免費的帳號,或是從數千個由志願者所架設的公開伺服器中選擇
-2. 在您自己的硬體上自行架設伺服器並建立帳號
-3. 訂閱 Element Matrix 服務託管平台並在自訂伺服氣上註冊帳號
+擁有您的資料
+您可以決定將您的資料與訊息儲存在何處。沒有資料挖礦或被第三方存取的風險。
-為何選擇 Element?
+Element 透過不同的方式讓您掌控一切:
+1. 在 Matrix 開發者架設的 matrix.org 公開伺服器上取得免費帳號,或是從數千個由志願者架設的公開伺服器中選擇
+2. 在您自己的 IT 基礎架構上執行伺服器來自行託管您的帳號
+3. 只要訂閱 Element Matrix Services 託管平台就可以在自訂的伺服器上註冊帳號
-擁有您的資料:您決定您的資料與訊息要放在哪裡。您擁有並控制它,而非某些科技巨頭會挖掘您的資料並將其售予第三方。
+開放訊息傳遞與協作
+您可以與 Matrix 網路上的任何人聊天,不論他們是使用 Element、其他 Matrix 應用程式或其他通訊應用程式。
-開放的即時通訊與協作:您可以與 Matrix 網路中的任何人聊天,不管他們是使用 Element 或其他 Matrix 應用程式都可以,或甚至是其他的訊息系統,如 Slack、IRC 或 XMPP 也都可以。
+超級安全
+真的端到端加密(僅有那些在對話中的可以解密訊息)以及交叉簽章裝置驗證。
-超級安全:即時的端到端加密(僅有參與對話的人可以解密訊息),以及交叉簽章以驗證對話參與者的裝置。
+完整的通訊與整合Complete communication and integration
+訊息傳遞、語音與視訊通話、檔案分享、畫面分享與超多的整合、機器人與小工具。建構聊天室、社群、保持聯絡並完成工作。
-完整通訊:即時通訊、語音與視訊通話、檔案分享、畫面分享與超多的整合、機器人與小工具。建立聊天室、保持聯繫並完成工作。
-
-無論您身在何處:無論您身在何處,都可以透過 https://app.element.io 來在所有裝置與網路上保持訊息歷史同步。
+從上次離開的地方開始
+無論您身在何處,都可以透過在您所有裝置與網頁 https://app.element.io 間完全同步的訊息歷史保持聯絡
diff --git a/fastlane/metadata/android/zh-Hant/short_description.txt b/fastlane/metadata/android/zh-Hant/short_description.txt
index 23bb82c04e..0d1f5bb7cd 100644
--- a/fastlane/metadata/android/zh-Hant/short_description.txt
+++ b/fastlane/metadata/android/zh-Hant/short_description.txt
@@ -1 +1 @@
-安全的去中心化聊天與 VoIP。確保您的資料不受第三方的影響。
+群組通訊軟體 - 訊息加密、群組聊天與視訊通話
diff --git a/fastlane/metadata/android/zh-Hant/title.txt b/fastlane/metadata/android/zh-Hant/title.txt
index 3be2260b73..47d8a6b3ad 100644
--- a/fastlane/metadata/android/zh-Hant/title.txt
+++ b/fastlane/metadata/android/zh-Hant/title.txt
@@ -1 +1 @@
-Element(曾名為 Riot.im)
+Element - 安全的通訊軟體
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 9d174797f7..e1e2fd2c75 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=81003f83b0056d20eedf48cddd4f52a9813163d4ba185bcf8abd34b8eeea4cbd
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-all.zip
+distributionSha256Sum=13bf8d3cf8eeeb5770d19741a59bde9bd966dd78d17f1bbad787a05ef19d1c2d
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/matrix-sdk-android-rx/build.gradle b/matrix-sdk-android-rx/build.gradle
index 37b0ff8d00..0d4aa7fc84 100644
--- a/matrix-sdk-android-rx/build.gradle
+++ b/matrix-sdk-android-rx/build.gradle
@@ -35,7 +35,7 @@ android {
dependencies {
implementation project(":matrix-sdk-android")
- implementation 'androidx.appcompat:appcompat:1.2.0'
+ implementation 'androidx.appcompat:appcompat:1.3.0'
implementation 'io.reactivex.rxjava2:rxkotlin:2.4.0'
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-rx2:$kotlin_coroutines_version"
diff --git a/matrix-sdk-android-rx/src/main/java/org/matrix/android/sdk/rx/RxCallbackBuilders.kt b/matrix-sdk-android-rx/src/main/java/org/matrix/android/sdk/rx/RxCallbackBuilders.kt
deleted file mode 100644
index ec30a31f6d..0000000000
--- a/matrix-sdk-android-rx/src/main/java/org/matrix/android/sdk/rx/RxCallbackBuilders.kt
+++ /dev/null
@@ -1,56 +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.rx
-
-import org.matrix.android.sdk.api.MatrixCallback
-import org.matrix.android.sdk.api.util.Cancelable
-import io.reactivex.Completable
-import io.reactivex.Single
-
-fun singleBuilder(builder: (MatrixCallback) -> Cancelable): Single = Single.create { emitter ->
- val callback = object : MatrixCallback {
- override fun onSuccess(data: T) {
- // Add `!!` to fix the warning:
- // "Type mismatch: type parameter with nullable bounds is used T is used where T was expected. This warning will become an error soon"
- emitter.onSuccess(data!!)
- }
-
- override fun onFailure(failure: Throwable) {
- emitter.tryOnError(failure)
- }
- }
- val cancelable = builder(callback)
- emitter.setCancellable {
- cancelable.cancel()
- }
-}
-
-fun completableBuilder(builder: (MatrixCallback) -> Cancelable): Completable = Completable.create { emitter ->
- val callback = object : MatrixCallback {
- override fun onSuccess(data: T) {
- emitter.onComplete()
- }
-
- override fun onFailure(failure: Throwable) {
- emitter.tryOnError(failure)
- }
- }
- val cancelable = builder(callback)
- emitter.setCancellable {
- cancelable.cancel()
- }
-}
diff --git a/matrix-sdk-android-rx/src/main/java/org/matrix/android/sdk/rx/RxSession.kt b/matrix-sdk-android-rx/src/main/java/org/matrix/android/sdk/rx/RxSession.kt
index 0fe2b01576..58fb760ff5 100644
--- a/matrix-sdk-android-rx/src/main/java/org/matrix/android/sdk/rx/RxSession.kt
+++ b/matrix-sdk-android-rx/src/main/java/org/matrix/android/sdk/rx/RxSession.kt
@@ -35,10 +35,12 @@ 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.RoomSummaryQueryParams
+import org.matrix.android.sdk.api.session.room.accountdata.RoomAccountDataEvent
import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
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.create.CreateRoomParams
+import org.matrix.android.sdk.api.session.space.SpaceSummaryQueryParams
import org.matrix.android.sdk.api.session.sync.SyncState
import org.matrix.android.sdk.api.session.user.model.User
import org.matrix.android.sdk.api.session.widgets.model.Widget
@@ -66,6 +68,13 @@ class RxSession(private val session: Session) {
}
}
+ fun liveSpaceSummaries(queryParams: SpaceSummaryQueryParams): Observable> {
+ return session.spaceService().getSpaceSummariesLive(queryParams).asObservable()
+ .startWithCallable {
+ session.spaceService().getSpaceSummaries(queryParams)
+ }
+ }
+
fun liveBreadcrumbs(queryParams: RoomSummaryQueryParams): Observable> {
return session.getBreadcrumbsLive(queryParams).asObservable()
.startWithCallable {
@@ -169,10 +178,17 @@ class RxSession(private val session: Session) {
}
}
- fun liveAccountData(types: Set): Observable> {
- return session.getLiveAccountDataEvents(types).asObservable()
+ fun liveUserAccountData(types: Set): Observable> {
+ return session.accountDataService().getLiveUserAccountDataEvents(types).asObservable()
.startWithCallable {
- session.getAccountDataEvents(types)
+ session.accountDataService().getUserAccountDataEvents(types)
+ }
+ }
+
+ fun liveRoomAccountData(types: Set): Observable> {
+ return session.accountDataService().getLiveRoomAccountDataEvents(types).asObservable()
+ .startWithCallable {
+ session.accountDataService().getRoomAccountDataEvents(types)
}
}
@@ -194,7 +210,7 @@ class RxSession(private val session: Session) {
fun liveSecretSynchronisationInfo(): Observable {
return Observable.combineLatest, Optional, Optional, SecretsSynchronisationInfo>(
- liveAccountData(setOf(MASTER_KEY_SSSS_NAME, USER_SIGNING_KEY_SSSS_NAME, SELF_SIGNING_KEY_SSSS_NAME, KEYBACKUP_SECRET_SSSS_NAME)),
+ liveUserAccountData(setOf(MASTER_KEY_SSSS_NAME, USER_SIGNING_KEY_SSSS_NAME, SELF_SIGNING_KEY_SSSS_NAME, KEYBACKUP_SECRET_SSSS_NAME)),
liveCrossSigningInfo(session.myUserId),
liveCrossSigningPrivateKeys(),
Function3 { _, crossSigningInfo, pInfo ->
diff --git a/matrix-sdk-android/build.gradle b/matrix-sdk-android/build.gradle
index 404939a985..fcfc77d34b 100644
--- a/matrix-sdk-android/build.gradle
+++ b/matrix-sdk-android/build.gradle
@@ -6,13 +6,10 @@ apply plugin: 'realm-android'
buildscript {
repositories {
- // mavenCentral()
- //noinspection GrDeprecatedAPIUsage
- jcenter()
+ mavenCentral()
}
dependencies {
- // Stick to this version until https://github.com/realm/realm-java/issues/7402 is fixed
- classpath "io.realm:realm-gradle-plugin:10.3.1"
+ classpath "io.realm:realm-gradle-plugin:10.5.0"
}
}
@@ -129,7 +126,7 @@ dependencies {
def lifecycle_version = '2.2.0'
def arch_version = '2.1.0'
def markwon_version = '3.1.0'
- def daggerVersion = '2.34'
+ def daggerVersion = '2.37'
def work_version = '2.5.0'
def retrofit_version = '2.9.0'
@@ -139,8 +136,8 @@ dependencies {
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version"
- implementation "androidx.appcompat:appcompat:1.2.0"
- implementation "androidx.core:core-ktx:1.3.2"
+ implementation "androidx.appcompat:appcompat:1.3.0"
+ implementation "androidx.core:core-ktx:1.5.0"
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
@@ -174,7 +171,7 @@ dependencies {
implementation "io.arrow-kt:arrow-instances-core:$arrow_version"
// olm lib is now hosted by jitpack: https://jitpack.io/#org.matrix.gitlab.matrix-org/olm
- implementation 'org.matrix.gitlab.matrix-org:olm:3.2.2'
+ implementation 'org.matrix.gitlab.matrix-org:olm:3.2.4'
// DI
implementation "com.google.dagger:dagger:$daggerVersion"
@@ -184,8 +181,11 @@ dependencies {
implementation 'com.jakewharton.timber:timber:4.7.1'
implementation 'com.facebook.stetho:stetho-okhttp3:1.6.0'
+ // Video compression
+ implementation 'com.otaliastudios:transcoder:0.10.3'
+
// Phone number https://github.com/google/libphonenumber
- implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.21'
+ implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.24'
testImplementation 'junit:junit:4.13.2'
testImplementation 'org.robolectric:robolectric:4.5.1'
@@ -203,7 +203,7 @@ dependencies {
androidTestImplementation 'androidx.test:rules:1.3.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
- androidTestImplementation 'org.amshove.kluent:kluent-android:1.61'
+ androidTestImplementation 'org.amshove.kluent:kluent-android:1.65'
androidTestImplementation 'io.mockk:mockk-android:1.11.0'
androidTestImplementation "androidx.arch.core:core-testing:$arch_version"
androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version"
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 33de345630..1d05e655af 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
@@ -26,6 +26,7 @@ import org.matrix.android.sdk.internal.di.MatrixModule
import org.matrix.android.sdk.internal.di.MatrixScope
import org.matrix.android.sdk.internal.di.NetworkModule
import org.matrix.android.sdk.internal.raw.RawModule
+import org.matrix.android.sdk.internal.util.system.SystemModule
@Component(modules = [
TestModule::class,
@@ -33,6 +34,7 @@ import org.matrix.android.sdk.internal.raw.RawModule
NetworkModule::class,
AuthModule::class,
RawModule::class,
+ SystemModule::class,
TestNetworkModule::class
])
@MatrixScope
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 122584142e..a2566c1414 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
@@ -18,6 +18,8 @@ package org.matrix.android.sdk.internal.crypto
import android.util.Log
import androidx.test.ext.junit.runners.AndroidJUnit4
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertNotNull
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -29,8 +31,6 @@ import org.matrix.android.sdk.common.CommonTestHelper
import org.matrix.android.sdk.common.CryptoTestHelper
import org.matrix.android.sdk.internal.crypto.model.event.EncryptedEventContent
import org.matrix.android.sdk.internal.crypto.model.event.RoomKeyContent
-import kotlin.test.assertEquals
-import kotlin.test.assertNotNull
@RunWith(AndroidJUnit4::class)
@FixMethodOrder(MethodSorters.JVM)
@@ -54,7 +54,7 @@ class PreShareKeysTest : InstrumentedTest {
&& it.getClearType() == EventType.ROOM_KEY
}
- assertEquals(0, preShareCount, "Bob should not have receive any key from alice at this point")
+ assertEquals("Bob should not have receive any key from alice at this point", 0, preShareCount)
Log.d("#Test", "Room Key Received from alice $preShareCount")
// Force presharing of new outbound key
@@ -78,14 +78,14 @@ class PreShareKeysTest : InstrumentedTest {
}
val content = latest?.getClearContent().toModel()
- assertNotNull(content, "Bob should have received and decrypted a room key event from alice")
- assertEquals(e2eRoomID, content.roomId, "Wrong room")
+ assertNotNull("Bob should have received and decrypted a room key event from alice", content)
+ assertEquals("Wrong room", e2eRoomID, content!!.roomId)
val megolmSessionId = content.sessionId!!
val sharedIndex = aliceSession.cryptoService().getSharedWithInfo(e2eRoomID, megolmSessionId)
.getObject(bobSession.myUserId, bobSession.sessionParams.deviceId)
- assertEquals(0, sharedIndex, "The session received by bob should match what alice sent")
+ assertEquals("The session received by bob should match what alice sent", 0, sharedIndex)
// Just send a real message as test
val sentEvent = mTestHelper.sendTextMessage(aliceSession.getRoom(e2eRoomID)!!, "Allo", 1).first()
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/ssss/QuadSTests.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/ssss/QuadSTests.kt
index eb4773f3c8..d14de30c90 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/ssss/QuadSTests.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/ssss/QuadSTests.kt
@@ -76,7 +76,7 @@ class QuadSTests : InstrumentedTest {
var accountData: UserAccountDataEvent? = null
val liveAccountData = runBlocking(Dispatchers.Main) {
- aliceSession.getLiveAccountDataEvent("${DefaultSharedSecretStorageService.KEY_ID_BASE}.$TEST_KEY_ID")
+ aliceSession.accountDataService().getLiveUserAccountDataEvent("${DefaultSharedSecretStorageService.KEY_ID_BASE}.$TEST_KEY_ID")
}
val accountDataObserver = Observer?> { t ->
if (t?.getOrNull()?.type == "${DefaultSharedSecretStorageService.KEY_ID_BASE}.$TEST_KEY_ID") {
@@ -104,7 +104,7 @@ class QuadSTests : InstrumentedTest {
val defaultDataLock = CountDownLatch(1)
val liveDefAccountData = runBlocking(Dispatchers.Main) {
- aliceSession.getLiveAccountDataEvent(DefaultSharedSecretStorageService.DEFAULT_KEY_ID)
+ aliceSession.accountDataService().getLiveUserAccountDataEvent(DefaultSharedSecretStorageService.DEFAULT_KEY_ID)
}
val accountDefDataObserver = Observer?> { t ->
if (t?.getOrNull()?.type == DefaultSharedSecretStorageService.DEFAULT_KEY_ID) {
@@ -206,7 +206,7 @@ class QuadSTests : InstrumentedTest {
)
}
- val accountDataEvent = aliceSession.getAccountDataEvent("my.secret")
+ val accountDataEvent = aliceSession.accountDataService().getUserAccountDataEvent("my.secret")
val encryptedContent = accountDataEvent?.content?.get("encrypted") as? Map<*, *>
assertEquals("Content should contains two encryptions", 2, encryptedContent?.keys?.size ?: 0)
@@ -280,7 +280,7 @@ class QuadSTests : InstrumentedTest {
var accountData: UserAccountDataEvent? = null
val liveAccountData = runBlocking(Dispatchers.Main) {
- session.getLiveAccountDataEvent(type)
+ session.accountDataService().getLiveUserAccountDataEvent(type)
}
val accountDataObserver = Observer?> { t ->
if (t?.getOrNull()?.type == type) {
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/QrCodeTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/QrCodeTest.kt
index ee604fc9ab..76bf6dc040 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/QrCodeTest.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/QrCodeTest.kt
@@ -226,12 +226,12 @@ class QrCodeTest : InstrumentedTest {
private fun checkHeader(byteArray: ByteArray) {
// MATRIX
- byteArray[0] shouldBeEqualTo 'M'.toByte()
- byteArray[1] shouldBeEqualTo 'A'.toByte()
- byteArray[2] shouldBeEqualTo 'T'.toByte()
- byteArray[3] shouldBeEqualTo 'R'.toByte()
- byteArray[4] shouldBeEqualTo 'I'.toByte()
- byteArray[5] shouldBeEqualTo 'X'.toByte()
+ byteArray[0] shouldBeEqualTo 'M'.code.toByte()
+ byteArray[1] shouldBeEqualTo 'A'.code.toByte()
+ byteArray[2] shouldBeEqualTo 'T'.code.toByte()
+ byteArray[3] shouldBeEqualTo 'R'.code.toByte()
+ byteArray[4] shouldBeEqualTo 'I'.code.toByte()
+ byteArray[5] shouldBeEqualTo 'X'.code.toByte()
// Version
byteArray[6] shouldBeEqualTo 2
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/internal/session/securestorage/SecretStoringUtilsTest.kt
new file mode 100644
index 0000000000..7ee6caed0d
--- /dev/null
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/session/securestorage/SecretStoringUtilsTest.kt
@@ -0,0 +1,184 @@
+/*
+ * 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.internal.session.securestorage
+
+import android.os.Build
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import org.amshove.kluent.shouldBeEqualTo
+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.internal.crypto.crosssigning.fromBase64
+import org.matrix.android.sdk.internal.crypto.crosssigning.toBase64NoPadding
+import java.io.ByteArrayOutputStream
+import java.util.UUID
+
+@RunWith(AndroidJUnit4::class)
+@FixMethodOrder(MethodSorters.JVM)
+class SecretStoringUtilsTest : InstrumentedTest {
+
+ private val buildVersionSdkIntProvider = TestBuildVersionSdkIntProvider()
+ private val secretStoringUtils = SecretStoringUtils(context(), buildVersionSdkIntProvider)
+
+ companion object {
+ const val TEST_STR = "This is something I want to store safely!"
+ }
+
+ @Test
+ fun testStringNominalCaseApi21() {
+ val alias = generateAlias()
+ buildVersionSdkIntProvider.value = Build.VERSION_CODES.LOLLIPOP
+ // Encrypt
+ val encrypted = secretStoringUtils.securelyStoreString(TEST_STR, alias)
+ // Decrypt
+ val decrypted = secretStoringUtils.loadSecureSecret(encrypted, alias)
+ decrypted shouldBeEqualTo TEST_STR
+ secretStoringUtils.safeDeleteKey(alias)
+ }
+
+ @Test
+ fun testStringNominalCaseApi23() {
+ val alias = generateAlias()
+ buildVersionSdkIntProvider.value = Build.VERSION_CODES.M
+ // Encrypt
+ val encrypted = secretStoringUtils.securelyStoreString(TEST_STR, alias)
+ // Decrypt
+ val decrypted = secretStoringUtils.loadSecureSecret(encrypted, alias)
+ decrypted shouldBeEqualTo TEST_STR
+ secretStoringUtils.safeDeleteKey(alias)
+ }
+
+ @Test
+ fun testStringNominalCaseApi30() {
+ val alias = generateAlias()
+ buildVersionSdkIntProvider.value = Build.VERSION_CODES.R
+ // Encrypt
+ val encrypted = secretStoringUtils.securelyStoreString(TEST_STR, alias)
+ // Decrypt
+ val decrypted = secretStoringUtils.loadSecureSecret(encrypted, alias)
+ decrypted shouldBeEqualTo TEST_STR
+ secretStoringUtils.safeDeleteKey(alias)
+ }
+
+ @Test
+ fun testStringMigration21_23() {
+ val alias = generateAlias()
+ buildVersionSdkIntProvider.value = Build.VERSION_CODES.LOLLIPOP
+ // Encrypt
+ val encrypted = secretStoringUtils.securelyStoreString(TEST_STR, alias)
+
+ // Simulate a system upgrade
+ buildVersionSdkIntProvider.value = Build.VERSION_CODES.M
+
+ // Decrypt
+ val decrypted = secretStoringUtils.loadSecureSecret(encrypted, alias)
+ decrypted shouldBeEqualTo TEST_STR
+ secretStoringUtils.safeDeleteKey(alias)
+ }
+
+ @Test
+ fun testObjectNominalCaseApi21() {
+ val alias = generateAlias()
+ buildVersionSdkIntProvider.value = Build.VERSION_CODES.LOLLIPOP
+
+ // Encrypt
+ val encrypted = ByteArrayOutputStream().also { outputStream ->
+ outputStream.use {
+ secretStoringUtils.securelyStoreObject(TEST_STR, alias, it)
+ }
+ }
+ .toByteArray()
+ .toBase64NoPadding()
+ // Decrypt
+ val decrypted = encrypted.fromBase64().inputStream().use {
+ secretStoringUtils.loadSecureSecret(it, alias)
+ }
+ decrypted shouldBeEqualTo TEST_STR
+ secretStoringUtils.safeDeleteKey(alias)
+ }
+
+ @Test
+ fun testObjectNominalCaseApi23() {
+ val alias = generateAlias()
+ buildVersionSdkIntProvider.value = Build.VERSION_CODES.M
+
+ // Encrypt
+ val encrypted = ByteArrayOutputStream().also { outputStream ->
+ outputStream.use {
+ secretStoringUtils.securelyStoreObject(TEST_STR, alias, it)
+ }
+ }
+ .toByteArray()
+ .toBase64NoPadding()
+ // Decrypt
+ val decrypted = encrypted.fromBase64().inputStream().use {
+ secretStoringUtils.loadSecureSecret(it, alias)
+ }
+ decrypted shouldBeEqualTo TEST_STR
+ secretStoringUtils.safeDeleteKey(alias)
+ }
+
+ @Test
+ fun testObjectNominalCaseApi30() {
+ val alias = generateAlias()
+ buildVersionSdkIntProvider.value = Build.VERSION_CODES.R
+
+ // Encrypt
+ val encrypted = ByteArrayOutputStream().also { outputStream ->
+ outputStream.use {
+ secretStoringUtils.securelyStoreObject(TEST_STR, alias, it)
+ }
+ }
+ .toByteArray()
+ .toBase64NoPadding()
+ // Decrypt
+ val decrypted = encrypted.fromBase64().inputStream().use {
+ secretStoringUtils.loadSecureSecret(it, alias)
+ }
+ decrypted shouldBeEqualTo TEST_STR
+ secretStoringUtils.safeDeleteKey(alias)
+ }
+
+ @Test
+ fun testObjectMigration21_23() {
+ val alias = generateAlias()
+ buildVersionSdkIntProvider.value = Build.VERSION_CODES.LOLLIPOP
+
+ // Encrypt
+ val encrypted = ByteArrayOutputStream().also { outputStream ->
+ outputStream.use {
+ secretStoringUtils.securelyStoreObject(TEST_STR, alias, it)
+ }
+ }
+ .toByteArray()
+ .toBase64NoPadding()
+
+ // Simulate a system upgrade
+ buildVersionSdkIntProvider.value = Build.VERSION_CODES.M
+
+ // Decrypt
+ val decrypted = encrypted.fromBase64().inputStream().use {
+ secretStoringUtils.loadSecureSecret(it, alias)
+ }
+ decrypted shouldBeEqualTo TEST_STR
+ secretStoringUtils.safeDeleteKey(alias)
+ }
+
+ private fun generateAlias() = UUID.randomUUID().toString()
+}
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/internal/session/securestorage/TestBuildVersionSdkIntProvider.kt
new file mode 100644
index 0000000000..b08c88fb24
--- /dev/null
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/session/securestorage/TestBuildVersionSdkIntProvider.kt
@@ -0,0 +1,25 @@
+/*
+ * 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.internal.session.securestorage
+
+import org.matrix.android.sdk.internal.util.system.BuildVersionSdkIntProvider
+
+class TestBuildVersionSdkIntProvider : BuildVersionSdkIntProvider {
+ var value: Int = 0
+
+ override fun get() = value
+}
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 ff07cf1d1d..ace48cef77 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
@@ -16,6 +16,7 @@
package org.matrix.android.sdk.session.room.timeline
+import org.junit.Assert.fail
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -29,7 +30,6 @@ import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings
import org.matrix.android.sdk.common.CommonTestHelper
import org.matrix.android.sdk.common.CryptoTestHelper
import java.util.concurrent.CountDownLatch
-import kotlin.test.fail
@RunWith(JUnit4::class)
@FixMethodOrder(MethodSorters.JVM)
@@ -80,6 +80,7 @@ class TimelineWithManyMembersTest : InstrumentedTest {
return@createEventListener true
} else {
fail("User " + session.myUserId + " decrypted as " + body + " CryptoError: " + it.root.mCryptoError)
+ false
}
} ?: return@createEventListener false
}
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
new file mode 100644
index 0000000000..a1744a0dae
--- /dev/null
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/space/SpaceCreationTest.kt
@@ -0,0 +1,222 @@
+/*
+ * Copyright 2021 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.session.space
+
+import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.runBlocking
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertNotNull
+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.ActiveSpaceFilter
+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.RoomSummaryQueryParams
+import org.matrix.android.sdk.api.session.room.model.GuestAccess
+import org.matrix.android.sdk.api.session.room.model.Membership
+import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
+import org.matrix.android.sdk.api.session.room.model.RoomGuestAccessContent
+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.RoomType
+import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
+import org.matrix.android.sdk.api.session.room.model.create.CreateRoomPreset
+import org.matrix.android.sdk.api.session.room.model.create.RoomCreateContent
+import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
+import org.matrix.android.sdk.api.session.space.JoinSpaceResult
+import org.matrix.android.sdk.common.CommonTestHelper
+import org.matrix.android.sdk.common.SessionTestParams
+
+@RunWith(JUnit4::class)
+@FixMethodOrder(MethodSorters.JVM)
+class SpaceCreationTest : InstrumentedTest {
+
+ private val commonTestHelper = CommonTestHelper(context())
+
+ @Test
+ fun createSimplePublicSpace() {
+ val session = commonTestHelper.createAccount("Hubble", SessionTestParams(true))
+ val roomName = "My Space"
+ val topic = "A public space for test"
+ var spaceId: String = ""
+ commonTestHelper.waitWithLatch {
+ GlobalScope.launch {
+ spaceId = session.spaceService().createSpace(roomName, topic, null, true)
+ // wait a bit to let the summary update it self :/
+ it.countDown()
+ }
+ }
+
+ val syncedSpace = session.spaceService().getSpace(spaceId)
+ commonTestHelper.waitWithLatch {
+ commonTestHelper.retryPeriodicallyWithLatch(it) {
+ syncedSpace?.asRoom()?.roomSummary()?.name != null
+ }
+ }
+ 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()
+ 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
+ }
+ }
+ 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
+
+ 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
+
+ assertEquals("Public space room should be world readable", RoomHistoryVisibility.WORLD_READABLE, historyVisibility)
+
+ commonTestHelper.signOutAndClose(session)
+ }
+
+ @Test
+ fun testJoinSimplePublicSpace() {
+ val aliceSession = commonTestHelper.createAccount("alice", SessionTestParams(true))
+ val bobSession = commonTestHelper.createAccount("bob", SessionTestParams(true))
+
+ val roomName = "My Space"
+ val topic = "A public space for test"
+ val spaceId: String
+ runBlocking {
+ spaceId = aliceSession.spaceService().createSpace(roomName, topic, null, true)
+ // wait a bit to let the summary update it self :/
+ delay(400)
+ }
+
+ // Try to join from bob, it's a public space no need to invite
+
+ val joinResult: JoinSpaceResult
+ runBlocking {
+ joinResult = bobSession.spaceService().joinSpace(spaceId)
+ }
+
+ assertEquals(JoinSpaceResult.Success, joinResult)
+
+ val spaceBobPov = bobSession.spaceService().getSpace(spaceId)
+ assertEquals("Room name should be set", roomName, spaceBobPov?.asRoom()?.roomSummary()?.name)
+ assertEquals("Room topic should be set", topic, spaceBobPov?.asRoom()?.roomSummary()?.topic)
+
+ commonTestHelper.signOutAndClose(aliceSession)
+ commonTestHelper.signOutAndClose(bobSession)
+ }
+
+ @Test
+ fun testSimplePublicSpaceWithChildren() {
+ val aliceSession = commonTestHelper.createAccount("alice", SessionTestParams(true))
+ val bobSession = commonTestHelper.createAccount("bob", SessionTestParams(true))
+
+ val roomName = "My Space"
+ val topic = "A public space for test"
+
+ val spaceId: String = runBlocking { aliceSession.spaceService().createSpace(roomName, topic, null, true) }
+ val syncedSpace = aliceSession.spaceService().getSpace(spaceId)
+
+ // create a room
+ var firstChild: String? = null
+ commonTestHelper.waitWithLatch {
+ GlobalScope.launch {
+ firstChild = aliceSession.createRoom(CreateRoomParams().apply {
+ this.name = "FirstRoom"
+ this.topic = "Description of first room"
+ this.preset = CreateRoomPreset.PRESET_PUBLIC_CHAT
+ })
+ it.countDown()
+ }
+ }
+
+ commonTestHelper.waitWithLatch {
+ GlobalScope.launch {
+ syncedSpace?.addChildren(firstChild!!, listOf(aliceSession.sessionParams.homeServerHost ?: ""), "a", true, suggested = true)
+ it.countDown()
+ }
+ }
+
+ var secondChild: String? = null
+ commonTestHelper.waitWithLatch {
+ GlobalScope.launch {
+ secondChild = aliceSession.createRoom(CreateRoomParams().apply {
+ this.name = "SecondRoom"
+ this.topic = "Description of second room"
+ this.preset = CreateRoomPreset.PRESET_PUBLIC_CHAT
+ })
+ it.countDown()
+ }
+ }
+
+ commonTestHelper.waitWithLatch {
+ GlobalScope.launch {
+ syncedSpace?.addChildren(secondChild!!, listOf(aliceSession.sessionParams.homeServerHost ?: ""), "b", false, suggested = true)
+ it.countDown()
+ }
+ }
+
+ // Try to join from bob, it's a public space no need to invite
+ var joinResult: JoinSpaceResult? = null
+ commonTestHelper.waitWithLatch {
+ GlobalScope.launch {
+ joinResult = bobSession.spaceService().joinSpace(spaceId)
+ // wait a bit to let the summary update it self :/
+ it.countDown()
+ }
+ }
+
+ assertEquals(JoinSpaceResult.Success, joinResult)
+
+ val spaceBobPov = bobSession.spaceService().getSpace(spaceId)
+ assertEquals("Room name should be set", roomName, spaceBobPov?.asRoom()?.roomSummary()?.name)
+ assertEquals("Room topic should be set", topic, spaceBobPov?.asRoom()?.roomSummary()?.topic)
+
+ // check if bob has joined automatically the first room
+
+ val bobMembershipFirstRoom = bobSession.getRoomSummary(firstChild!!)?.membership
+ assertEquals("Bob should have joined this room", Membership.JOIN, bobMembershipFirstRoom)
+ RoomSummaryQueryParams.Builder()
+
+ val childCount = bobSession.getRoomSummaries(
+ roomSummaryQueryParams {
+ activeSpaceFilter = ActiveSpaceFilter.ActiveSpace(spaceId)
+ }
+ ).size
+
+ assertEquals("Unexpected number of joined children", 1, childCount)
+
+ commonTestHelper.signOutAndClose(aliceSession)
+ commonTestHelper.signOutAndClose(bobSession)
+ }
+}
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/space/SpaceHierarchyTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/space/SpaceHierarchyTest.kt
new file mode 100644
index 0000000000..521b5805bd
--- /dev/null
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/space/SpaceHierarchyTest.kt
@@ -0,0 +1,472 @@
+/*
+ * Copyright 2021 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.session.space
+
+import android.util.Log
+import androidx.lifecycle.Observer
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.launch
+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.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.ActiveSpaceFilter
+import org.matrix.android.sdk.api.session.Session
+import org.matrix.android.sdk.api.session.room.model.RoomSummary
+import org.matrix.android.sdk.api.session.room.model.RoomType
+import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
+import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
+import org.matrix.android.sdk.common.CommonTestHelper
+import org.matrix.android.sdk.common.SessionTestParams
+
+@RunWith(JUnit4::class)
+@FixMethodOrder(MethodSorters.JVM)
+class SpaceHierarchyTest : InstrumentedTest {
+
+ private val commonTestHelper = CommonTestHelper(context())
+
+ @Test
+ fun createCanonicalChildRelation() {
+ val session = commonTestHelper.createAccount("John", SessionTestParams(true))
+ val spaceName = "My Space"
+ val topic = "A public space for test"
+ var spaceId: String = ""
+ commonTestHelper.waitWithLatch {
+ GlobalScope.launch {
+ spaceId = session.spaceService().createSpace(spaceName, topic, null, true)
+ it.countDown()
+ }
+ }
+
+ val syncedSpace = session.spaceService().getSpace(spaceId)
+
+ var roomId: String = ""
+ commonTestHelper.waitWithLatch {
+ GlobalScope.launch {
+ roomId = session.createRoom(CreateRoomParams().apply { name = "General" })
+ it.countDown()
+ }
+ }
+
+ val viaServers = listOf(session.sessionParams.homeServerHost ?: "")
+
+ commonTestHelper.waitWithLatch {
+ GlobalScope.launch {
+ syncedSpace!!.addChildren(roomId, viaServers, null, true)
+ it.countDown()
+ }
+ }
+
+ commonTestHelper.waitWithLatch {
+ GlobalScope.launch {
+ 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")
+ }
+
+ 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
+// fun testCreateChildRelations() {
+// val session = commonTestHelper.createAccount("Jhon", SessionTestParams(true))
+// val spaceName = "My Space"
+// val topic = "A public space for test"
+// Log.d("## TEST", "Before")
+//
+// var spaceId = ""
+// commonTestHelper.waitWithLatch {
+// GlobalScope.launch {
+// spaceId = session.spaceService().createSpace(spaceName, topic, null, true)
+// it.countDown()
+// }
+// }
+//
+// Log.d("## TEST", "created space $spaceId ${Thread.currentThread()}")
+// val syncedSpace = session.spaceService().getSpace(spaceId)
+//
+// val children = listOf("General" to true /*canonical*/, "Random" to false)
+//
+// // val roomIdList = children.map {
+// // runBlocking {
+// // session.createRoom(CreateRoomParams().apply { name = it.first })
+// // } to it.second
+// // }
+// val roomIdList = mutableListOf>()
+// commonTestHelper.waitWithLatch {
+// GlobalScope.launch {
+// children.forEach {
+// val rID = session.createRoom(CreateRoomParams().apply { name = it.first })
+// roomIdList.add(rID to it.second)
+// }
+// it.countDown()
+// }
+// }
+//
+// val viaServers = listOf(session.sessionParams.homeServerHost ?: "")
+//
+// commonTestHelper.waitWithLatch {
+// GlobalScope.launch {
+// roomIdList.forEach { entry ->
+// syncedSpace!!.addChildren(entry.first, viaServers, null, true)
+// }
+// it.countDown()
+// }
+// }
+//
+// commonTestHelper.waitWithLatch {
+// GlobalScope.launch {
+// roomIdList.forEach {
+// session.spaceService().setSpaceParent(it.first, spaceId, it.second, viaServers)
+// }
+// it.countDown()
+// }
+// }
+//
+// roomIdList.forEach {
+// val parents = session.getRoom(it.first)?.roomSummary()?.spaceParents
+// val canonicalParents = session.getRoom(it.first)?.roomSummary()?.spaceParents?.filter { it.canonical == true }
+//
+// assertNotNull(parents)
+// assertEquals("Unexpected number of parent", 1, parents!!.size)
+// assertEquals("Unexpected parent name", spaceName, parents.first().roomSummary?.name)
+// assertEquals("Parent of ${it.first} should be canonical ${it.second}", if (it.second) 1 else 0, canonicalParents?.size ?: 0)
+// }
+// }
+
+ @Test
+ fun testFilteringBySpace() {
+ val session = commonTestHelper.createAccount("John", SessionTestParams(true))
+
+ val spaceAInfo = createPublicSpace(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)
+ ))
+
+ val spaceCInfo = createPublicSpace(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 {
+ GlobalScope.launch {
+ 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 {
+ GlobalScope.launch {
+ orphan1 = session.createRoom(CreateRoomParams().apply { name = "O1" })
+ it.countDown()
+ }
+ }
+
+ var orphan2 = ""
+ commonTestHelper.waitWithLatch {
+ GlobalScope.launch {
+ orphan2 = session.createRoom(CreateRoomParams().apply { name = "O2" })
+ it.countDown()
+ }
+ }
+
+ val allRooms = session.getRoomSummaries(roomSummaryQueryParams { excludeType = listOf(RoomType.SPACE) })
+
+ assertEquals("Unexpected number of rooms", 9, allRooms.size)
+
+ val orphans = session.getFlattenRoomSummaryChildrenOf(null)
+
+ assertEquals("Unexpected number of orphan rooms", 2, orphans.size)
+ assertTrue("O1 should be an orphan", orphans.any { it.roomId == orphan1 })
+ assertTrue("O2 should be an orphan ${orphans.map { it.name }}", orphans.any { it.roomId == orphan2 })
+
+ val aChildren = session.getFlattenRoomSummaryChildrenOf(spaceAInfo.spaceId)
+
+ assertEquals("Unexpected number of flatten child rooms", 4, aChildren.size)
+ assertTrue("A1 should be a child of A", aChildren.any { it.name == "A1" })
+ assertTrue("A2 should be a child of A", aChildren.any { it.name == "A2" })
+ assertTrue("CA should be a grand child of A", aChildren.any { it.name == "C1" })
+ 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 {
+ GlobalScope.launch {
+ val a3 = session.createRoom(CreateRoomParams().apply { name = "A3" })
+ spaceA!!.addChildren(a3, viaServers, null, false)
+ it.countDown()
+ }
+ }
+
+ Thread.sleep(2_000)
+ val orphansUpdate = session.getRoomSummaries(roomSummaryQueryParams {
+ activeSpaceFilter = ActiveSpaceFilter.ActiveSpace(null)
+ })
+ assertEquals("Unexpected number of orphan rooms ${orphansUpdate.map { it.name }}", 2, orphansUpdate.size)
+ }
+
+ @Test
+ fun testBreakCycle() {
+ val session = commonTestHelper.createAccount("John", SessionTestParams(true))
+
+ val spaceAInfo = createPublicSpace(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)
+ ))
+
+ // add C as a subspace of A
+ val spaceA = session.spaceService().getSpace(spaceAInfo.spaceId)
+ val viaServers = listOf(session.sessionParams.homeServerHost ?: "")
+ commonTestHelper.waitWithLatch {
+ GlobalScope.launch {
+ 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 {
+ GlobalScope.launch {
+ val spaceC = session.spaceService().getSpace(spaceCInfo.spaceId)
+ spaceC!!.addChildren(spaceAInfo.spaceId, viaServers, null, true)
+ it.countDown()
+ }
+ }
+
+ Thread.sleep(1000)
+
+ // A -> C -> A
+
+ val aChildren = session.getFlattenRoomSummaryChildrenOf(spaceAInfo.spaceId)
+
+ assertEquals("Unexpected number of flatten child rooms ${aChildren.map { it.name }}", 4, aChildren.size)
+ assertTrue("A1 should be a child of A", aChildren.any { it.name == "A1" })
+ assertTrue("A2 should be a child of A", aChildren.any { it.name == "A2" })
+ assertTrue("CA should be a grand child of A", aChildren.any { it.name == "C1" })
+ assertTrue("A1 should be a grand child of A", aChildren.any { it.name == "C2" })
+ }
+
+ @Test
+ fun testLiveFlatChildren() {
+ val session = commonTestHelper.createAccount("John", SessionTestParams(true))
+
+ val spaceAInfo = createPublicSpace(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)
+ ))
+
+ // add B as a subspace of A
+ val spaceA = session.spaceService().getSpace(spaceAInfo.spaceId)
+ val viaServers = listOf(session.sessionParams.homeServerHost ?: "")
+ runBlocking {
+ spaceA!!.addChildren(spaceBInfo.spaceId, viaServers, null, true)
+ session.spaceService().setSpaceParent(spaceBInfo.spaceId, spaceAInfo.spaceId, true, viaServers)
+ }
+
+ val flatAChildren = runBlocking(Dispatchers.Main) {
+ session.getFlattenRoomSummaryChildrenOfLive(spaceAInfo.spaceId)
+ }
+
+ commonTestHelper.waitWithLatch { latch ->
+
+ val childObserver = object : Observer> {
+ override fun onChanged(children: List?) {
+// Log.d("## TEST", "Space A flat children update : ${children?.map { it.name }}")
+ System.out.println("## TEST | Space A flat children update : ${children?.map { it.name }}")
+ if (children?.any { it.name == "C1" } == true && children.any { it.name == "C2" }) {
+ // B1 has been added live!
+ latch.countDown()
+ flatAChildren.removeObserver(this)
+ }
+ }
+ }
+
+ val spaceCInfo = createPublicSpace(session, "SpaceC", listOf(
+ Triple("C1", true /*auto-join*/, true/*canonical*/),
+ Triple("C2", true, true)
+ ))
+
+ // add C as subspace of B
+ runBlocking {
+ 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
+
+ GlobalScope.launch(Dispatchers.Main) { flatAChildren.observeForever(childObserver) }
+ }
+
+ // Test part one of the rooms
+
+ val bRoomId = spaceBInfo.roomIds.first()
+ val bRoom = session.getRoom(bRoomId)
+
+ commonTestHelper.waitWithLatch { latch ->
+
+ val childObserver = object : Observer> {
+ override fun onChanged(children: List?) {
+ System.out.println("## TEST | Space A flat children update : ${children?.map { it.name }}")
+ if (children?.any { it.roomId == bRoomId } == false) {
+ // B1 has been added live!
+ latch.countDown()
+ flatAChildren.removeObserver(this)
+ }
+ }
+ }
+
+ // part from b room
+ runBlocking {
+ bRoom!!.leave(null)
+ }
+ // The room should have disapear from flat children
+ GlobalScope.launch(Dispatchers.Main) { flatAChildren.observeForever(childObserver) }
+ }
+ }
+
+ data class TestSpaceCreationResult(
+ val spaceId: String,
+ val roomIds: List
+ )
+
+ private fun createPublicSpace(session: Session,
+ spaceName: String,
+ childInfo: List>
+ /** Name, auto-join, canonical*/
+ ): TestSpaceCreationResult {
+ var spaceId = ""
+ commonTestHelper.waitWithLatch {
+ GlobalScope.launch {
+ spaceId = session.spaceService().createSpace(spaceName, "Test Topic", null, true)
+ it.countDown()
+ }
+ }
+
+ val syncedSpace = session.spaceService().getSpace(spaceId)
+ val viaServers = listOf(session.sessionParams.homeServerHost ?: "")
+
+ val roomIds =
+ childInfo.map { entry ->
+ var roomId = ""
+ commonTestHelper.waitWithLatch {
+ GlobalScope.launch {
+ roomId = session.createRoom(CreateRoomParams().apply { name = entry.first })
+ it.countDown()
+ }
+ }
+ roomId
+ }
+
+ roomIds.forEachIndexed { index, roomId ->
+ runBlocking {
+ syncedSpace!!.addChildren(roomId, viaServers, null, childInfo[index].second)
+ val canonical = childInfo[index].third
+ if (canonical != null) {
+ session.spaceService().setSpaceParent(roomId, spaceId, canonical, viaServers)
+ }
+ }
+ }
+ return TestSpaceCreationResult(spaceId, roomIds)
+ }
+
+ @Test
+ fun testRootSpaces() {
+ val session = commonTestHelper.createAccount("John", SessionTestParams(true))
+
+ val spaceAInfo = createPublicSpace(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)
+ ))
+
+ val spaceCInfo = createPublicSpace(session, "SpaceC", listOf(
+ Triple("C1", true /*auto-join*/, true/*canonical*/),
+ Triple("C2", true, true)
+ ))
+
+ val viaServers = listOf(session.sessionParams.homeServerHost ?: "")
+
+ // add C as subspace of B
+ runBlocking {
+ val spaceB = session.spaceService().getSpace(spaceBInfo.spaceId)
+ spaceB!!.addChildren(spaceCInfo.spaceId, viaServers, null, true)
+ }
+
+ Thread.sleep(2000)
+ // + A
+ // a1, a2
+ // + B
+ // b1, b2, b3
+ // + C
+ // + c1, c2
+
+ val rootSpaces = session.spaceService().getRootSpaceSummaries()
+
+ assertEquals("Unexpected number of root spaces ${rootSpaces.map { it.name }}", 2, rootSpaces.size)
+ }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt
index a7f5163774..5e35917243 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt
@@ -51,11 +51,15 @@ interface AuthenticationService {
/**
* Return a LoginWizard, to login to the homeserver. The login flow has to be retrieved first.
+ *
+ * See [LoginWizard] for more details
*/
fun getLoginWizard(): LoginWizard
/**
* Return a RegistrationWizard, to create an matrix account on the homeserver. The login flow has to be retrieved first.
+ *
+ * See [RegistrationWizard] for more details.
*/
fun getRegistrationWizard(): RegistrationWizard
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 cfaf74ce24..a0733dda97 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
@@ -48,14 +48,35 @@ data class SsoIdentityProvider(
*/
@Json(name = "brand") val brand: String?
-) : Parcelable {
+) : Parcelable, Comparable {
companion object {
- const val BRAND_GOOGLE = "org.matrix.google"
- const val BRAND_GITHUB = "org.matrix.github"
- const val BRAND_APPLE = "org.matrix.apple"
- const val BRAND_FACEBOOK = "org.matrix.facebook"
- const val BRAND_TWITTER = "org.matrix.twitter"
- const val BRAND_GITLAB = "org.matrix.gitlab"
+ const val BRAND_GOOGLE = "google"
+ const val BRAND_GITHUB = "github"
+ const val BRAND_APPLE = "apple"
+ const val BRAND_FACEBOOK = "facebook"
+ const val BRAND_TWITTER = "twitter"
+ const val BRAND_GITLAB = "gitlab"
+ }
+
+ override fun compareTo(other: SsoIdentityProvider): Int {
+ return other.toPriority().compareTo(toPriority())
+ }
+
+ private fun toPriority(): Int {
+ return when (brand) {
+ // We are on Android, so user is more likely to have a Google account
+ BRAND_GOOGLE -> 5
+ // Facebook is also an important SSO provider
+ BRAND_FACEBOOK -> 4
+ // Twitter is more for professionals
+ BRAND_TWITTER -> 3
+ // Here it's very for techie people
+ BRAND_GITHUB,
+ BRAND_GITLAB -> 2
+ // And finally, if the account has been created with an iPhone...
+ BRAND_APPLE -> 1
+ else -> 0
+ }
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/login/LoginProfileInfo.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/login/LoginProfileInfo.kt
new file mode 100644
index 0000000000..288a6d1232
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/login/LoginProfileInfo.kt
@@ -0,0 +1,23 @@
+/*
+ * 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.auth.login
+
+data class LoginProfileInfo(
+ val matrixId: String,
+ val displayName: String?,
+ val fullAvatarUrl: String?
+)
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 9c96cba40c..a2a9373837 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
@@ -17,34 +17,51 @@
package org.matrix.android.sdk.api.auth.login
import org.matrix.android.sdk.api.session.Session
-import org.matrix.android.sdk.api.util.Cancelable
+/**
+ * Set of methods to be able to login to an existing account on a homeserver.
+ *
+ * More documentation can be found in the file https://github.com/vector-im/element-android/blob/main/docs/signin.md
+ */
interface LoginWizard {
+ /**
+ * Get some information about a matrixId: displayName and avatar url
+ */
+ suspend fun getProfileInfo(matrixId: String): LoginProfileInfo
/**
- * @param login the login field
- * @param password the password field
+ * Login to the homeserver.
+ *
+ * @param login the login field. Can be a user name, or a msisdn (email or phone number) associated to the account
+ * @param password the password of the account
* @param deviceName the initial device name
- * @param callback the matrix callback on which you'll receive the result of authentication.
- * @return a [Cancelable]
+ * @return a [Session] if the login is successful
*/
suspend fun login(login: String,
password: String,
deviceName: String): Session
/**
- * Exchange a login token to an access token
+ * Exchange a login token to an access token.
+ *
+ * @param loginToken login token, obtain when login has happen in a WebView, using SSO
+ * @return a [Session] if the login is successful
*/
suspend fun loginWithToken(loginToken: String): Session
/**
- * Reset user password
+ * Ask the homeserver to reset the user password. The password will not be reset until
+ * [resetPasswordMailConfirmed] is successfully called.
+ *
+ * @param email an email previously associated to the account the user wants the password to be reset.
+ * @param newPassword the desired new password
*/
suspend fun resetPassword(email: String,
newPassword: String)
/**
* Confirm the new password, once the user has checked their email
+ * When this method succeed, tha account password will be effectively modified.
*/
suspend fun resetPasswordMailConfirmed()
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/registration/RegistrationWizard.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/registration/RegistrationWizard.kt
index 38a5a77291..621253faa5 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/registration/RegistrationWizard.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/registration/RegistrationWizard.kt
@@ -16,30 +16,98 @@
package org.matrix.android.sdk.api.auth.registration
+/**
+ * Set of methods to be able to create an account on a homeserver.
+ *
+ * Common scenario to register an account successfully:
+ * - Call [getRegistrationFlow] to check that you application supports all the mandatory registration stages
+ * - Call [createAccount] to start the account creation
+ * - Fulfill all mandatory stages using the methods [performReCaptcha] [acceptTerms] [dummy], etc.
+ *
+ * More documentation can be found in the file https://github.com/vector-im/element-android/blob/main/docs/signup.md
+ * and https://matrix.org/docs/spec/client_server/latest#account-registration-and-management
+ */
interface RegistrationWizard {
-
+ /**
+ * Call this method to get the possible registration flow of the current homeserver.
+ * It can be useful to ensure that your application implementation supports all the stages
+ * required to create an account. If it is not the case, you will have to use the web fallback
+ * to let the user create an account with your application.
+ * See [org.matrix.android.sdk.api.auth.AuthenticationService.getFallbackUrl]
+ */
suspend fun getRegistrationFlow(): RegistrationResult
- suspend fun createAccount(userName: String, password: String, initialDeviceDisplayName: String?): RegistrationResult
-
- suspend fun performReCaptcha(response: String): RegistrationResult
-
- suspend fun acceptTerms(): RegistrationResult
-
- suspend fun dummy(): RegistrationResult
-
- suspend fun addThreePid(threePid: RegisterThreePid): RegistrationResult
-
- suspend fun sendAgainThreePid(): RegistrationResult
-
- suspend fun handleValidateThreePid(code: String): RegistrationResult
-
- suspend fun checkIfEmailHasBeenValidated(delayMillis: Long): RegistrationResult
-
+ /**
+ * Can be call to check is the desired userName is available for registration on the current homeserver.
+ * It may also fails if the desired userName is not correctly formatted or does not follow any restriction on
+ * the homeserver. Ex: userName with only digits may be rejected.
+ * @param userName the desired username. Ex: "alice"
+ */
suspend fun registrationAvailable(userName: String): RegistrationAvailability
+ /**
+ * This is the first method to call in order to create an account and start the registration process.
+ *
+ * @param userName the desired username. Ex: "alice"
+ * @param password the desired password
+ * @param initialDeviceDisplayName the device display name
+ */
+ suspend fun createAccount(userName: String?,
+ password: String?,
+ initialDeviceDisplayName: String?): RegistrationResult
+
+ /**
+ * Perform the "m.login.recaptcha" stage.
+ *
+ * @param response the response from ReCaptcha
+ */
+ suspend fun performReCaptcha(response: String): RegistrationResult
+
+ /**
+ * Perform the "m.login.terms" stage.
+ */
+ suspend fun acceptTerms(): RegistrationResult
+
+ /**
+ * Perform the "m.login.dummy" stage.
+ */
+ suspend fun dummy(): RegistrationResult
+
+ /**
+ * Perform the "m.login.email.identity" or "m.login.msisdn" stage.
+ *
+ * @param threePid the threePid to add to the account. If this is an email, the homeserver will send an email
+ * to validate it. For a msisdn a SMS will be sent.
+ */
+ suspend fun addThreePid(threePid: RegisterThreePid): RegistrationResult
+
+ /**
+ * Ask the homeserver to send again the current threePid (email or msisdn).
+ */
+ suspend fun sendAgainThreePid(): RegistrationResult
+
+ /**
+ * Send the code received by SMS to validate a msisdn.
+ * If the code is correct, the registration request will be executed to validate the msisdn.
+ */
+ suspend fun handleValidateThreePid(code: String): RegistrationResult
+
+ /**
+ * Useful to poll the homeserver when waiting for the email to be validated by the user.
+ * Once the email is validated, this method will return successfully.
+ * @param delayMillis the SDK can wait before sending the request
+ */
+ suspend fun checkIfEmailHasBeenValidated(delayMillis: Long): RegistrationResult
+
+ /**
+ * This is the current ThreePid, waiting for validation. The SDK will store it in database, so it can be
+ * restored even if the app has been killed during the registration
+ */
val currentThreePid: String?
- // True when login and password has been sent with success to the homeserver
+ /**
+ * True when login and password have been sent with success to the homeserver, i.e. [createAccount] has been
+ * called successfully.
+ */
val isRegistrationStarted: Boolean
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Failure.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Failure.kt
index b241903364..8f1bbb6941 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Failure.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Failure.kt
@@ -32,7 +32,6 @@ import java.io.IOException
*/
sealed class Failure(cause: Throwable? = null) : Throwable(cause = cause) {
data class Unknown(val throwable: Throwable? = null) : Failure(throwable)
- data class Cancelled(val throwable: Throwable? = null) : Failure(throwable)
data class UnrecognizedCertificateFailure(val url: String, val fingerprint: Fingerprint) : Failure()
data class NetworkConnection(val ioException: IOException? = null) : Failure(ioException)
data class ServerError(val error: MatrixError, val httpCode: Int) : Failure(RuntimeException(error.toString()))
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/MatrixError.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/MatrixError.kt
index 3820a442aa..73b0fe0a7c 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/MatrixError.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/MatrixError.kt
@@ -41,7 +41,7 @@ data class MatrixError(
// For M_LIMIT_EXCEEDED
@Json(name = "retry_after_ms") val retryAfterMillis: Long? = null,
// For M_UNKNOWN_TOKEN
- @Json(name = "soft_logout") val isSoftLogout: Boolean = false,
+ @Json(name = "soft_logout") val isSoftLogout: Boolean? = null,
// For M_INVALID_PEPPER
// {"error": "pepper does not match 'erZvr'", "lookup_pepper": "pQgMS", "algorithm": "sha256", "errcode": "M_INVALID_PEPPER"}
@Json(name = "lookup_pepper") val newLookupPepper: String? = null,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/query/ActiveSpaceFilter.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/query/ActiveSpaceFilter.kt
new file mode 100644
index 0000000000..48619b9394
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/query/ActiveSpaceFilter.kt
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2021 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.api.query
+
+sealed class ActiveSpaceFilter {
+ object None : ActiveSpaceFilter()
+ data class ActiveSpace(val currentSpaceId: String?) : ActiveSpaceFilter()
+ data class ExcludeSpace(val spaceId: String) : ActiveSpaceFilter()
+}
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 a15799d862..2f981ffbbe 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt
@@ -24,7 +24,7 @@ import org.matrix.android.sdk.api.failure.GlobalError
import org.matrix.android.sdk.api.federation.FederationService
import org.matrix.android.sdk.api.pushrules.PushRuleService
import org.matrix.android.sdk.api.session.account.AccountService
-import org.matrix.android.sdk.api.session.accountdata.AccountDataService
+import org.matrix.android.sdk.api.session.accountdata.SessionAccountDataService
import org.matrix.android.sdk.api.session.cache.CacheService
import org.matrix.android.sdk.api.session.call.CallSignalingService
import org.matrix.android.sdk.api.session.content.ContentUploadStateTracker
@@ -39,6 +39,7 @@ import org.matrix.android.sdk.api.session.identity.IdentityService
import org.matrix.android.sdk.api.session.initsync.InitialSyncProgressService
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
import org.matrix.android.sdk.api.session.permalinks.PermalinkService
import org.matrix.android.sdk.api.session.profile.ProfileService
import org.matrix.android.sdk.api.session.pushers.PushersService
@@ -48,6 +49,7 @@ 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.sync.FilterService
import org.matrix.android.sdk.api.session.sync.SyncState
import org.matrix.android.sdk.api.session.terms.TermsService
@@ -76,7 +78,6 @@ interface Session :
InitialSyncProgressService,
HomeServerCapabilitiesService,
SecureStorageService,
- AccountDataService,
AccountService {
/**
@@ -227,6 +228,21 @@ interface Session :
*/
fun thirdPartyService(): ThirdPartyService
+ /**
+ * Returns the space service associated with the session
+ */
+ fun spaceService(): SpaceService
+
+ /**
+ * Returns the open id service associated with the session
+ */
+ fun openIdService(): OpenIdService
+
+ /**
+ * Returns the account data service associated with the session
+ */
+ fun accountDataService(): SessionAccountDataService
+
/**
* Add a listener to the session.
* @param listener the listener to add.
@@ -249,13 +265,18 @@ interface Session :
/**
* A global session listener to get notified for some events.
*/
- interface Listener {
+ interface Listener : SessionLifecycleObserver {
+ /**
+ * Called when the session received new invites to room so the client can react to it once.
+ */
+ fun onNewInvitedRoom(session: Session, roomId: String) = Unit
+
/**
* Possible cases:
* - The access token is not valid anymore,
* - a M_CONSENT_NOT_GIVEN error has been received from the homeserver
*/
- fun onGlobalError(globalError: GlobalError)
+ fun onGlobalError(session: Session, globalError: GlobalError) = Unit
}
val sharedSecretStorageService: SharedSecretStorageService
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionLifecycleObserver.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/SessionLifecycleObserver.kt
similarity index 80%
rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionLifecycleObserver.kt
rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/SessionLifecycleObserver.kt
index cb37fbec75..b76e454e4b 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionLifecycleObserver.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/SessionLifecycleObserver.kt
@@ -14,20 +14,19 @@
* limitations under the License.
*/
-package org.matrix.android.sdk.internal.session
+package org.matrix.android.sdk.api.session
import androidx.annotation.MainThread
/**
* This defines methods associated with some lifecycle events of a session.
- * A list of SessionLifecycle will be injected into [DefaultSession]
*/
-internal interface SessionLifecycleObserver {
+interface SessionLifecycleObserver {
/*
Called when the session is opened
*/
@MainThread
- fun onSessionStarted() {
+ fun onSessionStarted(session: Session) {
// noop
}
@@ -35,7 +34,7 @@ internal interface SessionLifecycleObserver {
Called when the session is cleared
*/
@MainThread
- fun onClearCache() {
+ fun onClearCache(session: Session) {
// noop
}
@@ -43,7 +42,7 @@ internal interface SessionLifecycleObserver {
Called when the session is closed
*/
@MainThread
- fun onSessionStopped() {
+ fun onSessionStopped(session: Session) {
// noop
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/accountdata/SessionAccountDataService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/accountdata/SessionAccountDataService.kt
new file mode 100644
index 0000000000..2ffb9112d1
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/accountdata/SessionAccountDataService.kt
@@ -0,0 +1,66 @@
+/*
+ * 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.accountdata
+
+import androidx.lifecycle.LiveData
+import org.matrix.android.sdk.api.session.events.model.Content
+import org.matrix.android.sdk.api.session.room.accountdata.RoomAccountDataEvent
+import org.matrix.android.sdk.api.util.Optional
+
+/**
+ * This service is attached globally to the session.
+ */
+interface SessionAccountDataService {
+ /**
+ * Retrieve the account data with the provided type or null if not found
+ */
+ fun getUserAccountDataEvent(type: String): UserAccountDataEvent?
+
+ /**
+ * Observe the account data with the provided type
+ */
+ fun getLiveUserAccountDataEvent(type: String): LiveData>
+
+ /**
+ * Retrieve the account data with the provided types. The return list can have a different size that
+ * the size of the types set, because some AccountData may not exist.
+ * If an empty set is provided, all the AccountData are retrieved
+ */
+ fun getUserAccountDataEvents(types: Set): List
+
+ /**
+ * Observe the account data with the provided types. If an empty set is provided, all the AccountData are observed
+ */
+ fun getLiveUserAccountDataEvents(types: Set): LiveData>
+
+ /**
+ * Retrieve the room account data with the provided types. The return list can have a different size that
+ * the size of the types set, because some AccountData may not exist.
+ * If an empty set is provided, all the room AccountData are retrieved
+ */
+ fun getRoomAccountDataEvents(types: Set): List
+
+ /**
+ * Observe the room account data with the provided types. If an empty set is provided, AccountData of every room are observed
+ */
+ fun getLiveRoomAccountDataEvents(types: Set): LiveData>
+
+ /**
+ * Update the account data with the provided type and the provided account data content
+ */
+ suspend fun updateUserAccountData(type: String, content: Content)
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/accountdata/UserAccountDataEvent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/accountdata/UserAccountDataEvent.kt
index 744e3e5379..77381a28c4 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/accountdata/UserAccountDataEvent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/accountdata/UserAccountDataEvent.kt
@@ -22,7 +22,7 @@ import org.matrix.android.sdk.api.session.events.model.Content
/**
* This is a simplified Event with just a type and a content.
- * Currently used types are defined in [UserAccountDataTypes].
+ * Currently used types are defined in [UserAccountDataTypes]
*/
@JsonClass(generateAdapter = true)
data class UserAccountDataEvent(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/CallIdGenerator.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/CallIdGenerator.kt
new file mode 100644
index 0000000000..43e6872525
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/CallIdGenerator.kt
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2021 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.api.session.call
+
+import java.util.UUID
+
+object CallIdGenerator {
+ fun generate() = UUID.randomUUID().toString()
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/CallListener.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/CallListener.kt
index 303add747f..d17be59cd4 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/CallListener.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/CallListener.kt
@@ -17,6 +17,7 @@
package org.matrix.android.sdk.api.session.call
import org.matrix.android.sdk.api.session.room.model.call.CallAnswerContent
+import org.matrix.android.sdk.api.session.room.model.call.CallAssertedIdentityContent
import org.matrix.android.sdk.api.session.room.model.call.CallCandidatesContent
import org.matrix.android.sdk.api.session.room.model.call.CallHangupContent
import org.matrix.android.sdk.api.session.room.model.call.CallInviteContent
@@ -61,4 +62,9 @@ interface CallListener {
* Called when the call has been managed by an other session
*/
fun onCallManagedByOtherSession(callId: String)
+
+ /**
+ * Called when an asserted identity event is received
+ */
+ fun onCallAssertedIdentityReceived(callAssertedIdentityContent: CallAssertedIdentityContent)
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/CallSignalingService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/CallSignalingService.kt
index dc67aa536a..c34744e75f 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/CallSignalingService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/CallSignalingService.kt
@@ -20,8 +20,6 @@ interface CallSignalingService {
suspend fun getTurnServer(): TurnServerResponse
- fun getPSTNProtocolChecker(): PSTNProtocolChecker
-
/**
* Create an outgoing call
*/
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/MxCall.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/MxCall.kt
index 7533619eb0..fcc9f7072d 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/MxCall.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/MxCall.kt
@@ -26,8 +26,12 @@ interface MxCallDetail {
val callId: String
val isOutgoing: Boolean
val roomId: String
- val opponentUserId: String
val isVideoCall: Boolean
+ val ourPartyId: String
+ val opponentPartyId: Optional?
+ val opponentVersion: Int
+ val opponentUserId: String
+ val capabilities: CallCapabilities?
}
/**
@@ -39,12 +43,6 @@ interface MxCall : MxCallDetail {
const val VOIP_PROTO_VERSION = 1
}
- val ourPartyId: String
- var opponentPartyId: Optional?
- var opponentVersion: Int
-
- var capabilities: CallCapabilities?
-
var state: CallState
/**
@@ -91,8 +89,12 @@ interface MxCall : MxCallDetail {
/**
* Send a m.call.replaces event to initiate call transfer.
+ * See [org.matrix.android.sdk.api.session.room.model.call.CallReplacesContent] for documentation about the parameters
*/
- suspend fun transfer(targetUserId: String, targetRoomId: String?)
+ suspend fun transfer(targetUserId: String,
+ targetRoomId: String?,
+ createCallId: String?,
+ awaitCallId: String?)
fun addListener(listener: StateListener)
fun removeListener(listener: StateListener)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/PSTNProtocolChecker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/PSTNProtocolChecker.kt
deleted file mode 100644
index 6627f62e24..0000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/PSTNProtocolChecker.kt
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (c) 2021 The Matrix.org Foundation C.I.C.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.matrix.android.sdk.api.session.call
-
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.delay
-import kotlinx.coroutines.launch
-import org.matrix.android.sdk.api.extensions.tryOrNull
-import org.matrix.android.sdk.api.session.room.model.thirdparty.ThirdPartyProtocol
-import org.matrix.android.sdk.internal.session.SessionScope
-import org.matrix.android.sdk.internal.session.thirdparty.GetThirdPartyProtocolsTask
-import org.matrix.android.sdk.internal.task.TaskExecutor
-import timber.log.Timber
-import java.util.concurrent.atomic.AtomicBoolean
-import javax.inject.Inject
-
-private const val PSTN_VECTOR_KEY = "im.vector.protocol.pstn"
-private const val PSTN_MATRIX_KEY = "m.protocol.pstn"
-
-/**
- * This class is responsible for checking if the HS support the PSTN protocol.
- * As long as the request succeed, it'll check only once by session.
- */
-@SessionScope
-class PSTNProtocolChecker @Inject internal constructor(private val taskExecutor: TaskExecutor,
- private val getThirdPartyProtocolsTask: GetThirdPartyProtocolsTask) {
-
- interface Listener {
- fun onPSTNSupportUpdated()
- }
-
- private var alreadyChecked = AtomicBoolean(false)
-
- private val pstnSupportListeners = mutableListOf()
-
- fun addListener(listener: Listener) {
- pstnSupportListeners.add(listener)
- }
-
- fun removeListener(listener: Listener) {
- pstnSupportListeners.remove(listener)
- }
-
- var supportedPSTNProtocol: String? = null
- private set
-
- fun checkForPSTNSupportIfNeeded() {
- if (alreadyChecked.get()) return
- taskExecutor.executorScope.checkForPSTNSupport()
- }
-
- private fun CoroutineScope.checkForPSTNSupport() = launch {
- try {
- supportedPSTNProtocol = getSupportedPSTN(3)
- alreadyChecked.set(true)
- if (supportedPSTNProtocol != null) {
- pstnSupportListeners.forEach {
- tryOrNull { it.onPSTNSupportUpdated() }
- }
- }
- } catch (failure: Throwable) {
- Timber.v("Fail to get supported PSTN, will check again next time.")
- }
- }
-
- private suspend fun getSupportedPSTN(maxTries: Int): String? {
- val thirdPartyProtocols: Map = try {
- getThirdPartyProtocolsTask.execute(Unit)
- } catch (failure: Throwable) {
- if (maxTries == 1) {
- throw failure
- } else {
- // Wait for 10s before trying again
- delay(10_000L)
- return getSupportedPSTN(maxTries - 1)
- }
- }
- return when {
- thirdPartyProtocols.containsKey(PSTN_VECTOR_KEY) -> PSTN_VECTOR_KEY
- thirdPartyProtocols.containsKey(PSTN_MATRIX_KEY) -> PSTN_MATRIX_KEY
- else -> null
- }
- }
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/content/ContentUploadStateTracker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/content/ContentUploadStateTracker.kt
index 924da6c19b..ec63eb0be2 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/content/ContentUploadStateTracker.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/content/ContentUploadStateTracker.kt
@@ -31,6 +31,8 @@ interface ContentUploadStateTracker {
sealed class State {
object Idle : State()
object EncryptingThumbnail : State()
+ object CompressingImage : State()
+ data class CompressingVideo(val percent: Float) : State()
data class UploadingThumbnail(val current: Long, val total: Long) : State()
data class Encrypting(val current: Long, val total: Long) : State()
data class Uploading(val current: Long, val total: Long) : State()
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 286d3d9f72..7d9bc33ba3 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
@@ -42,7 +42,6 @@ import org.matrix.android.sdk.internal.crypto.model.event.RoomKeyWithHeldContent
import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo
import org.matrix.android.sdk.internal.crypto.model.rest.DevicesListResponse
import org.matrix.android.sdk.internal.crypto.model.rest.RoomKeyRequestBody
-import kotlin.jvm.Throws
interface CryptoService {
@@ -78,9 +77,11 @@ interface CryptoService {
fun getDeviceTrackingStatus(userId: String): Int
- fun importRoomKeys(roomKeysAsArray: ByteArray, password: String, progressListener: ProgressListener?, callback: MatrixCallback)
+ suspend fun importRoomKeys(roomKeysAsArray: ByteArray,
+ password: String,
+ progressListener: ProgressListener?): ImportRoomKeysResult
- fun exportRoomKeys(password: String, callback: MatrixCallback)
+ suspend fun exportRoomKeys(password: String): ByteArray
fun setRoomBlacklistUnverifiedDevices(roomId: String)
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 89b873febb..6400dd6444 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
@@ -28,6 +28,8 @@ import org.matrix.android.sdk.internal.crypto.algorithms.olm.OlmDecryptionResult
import org.matrix.android.sdk.internal.crypto.model.event.EncryptedEventContent
import org.matrix.android.sdk.internal.di.MoshiProvider
import org.json.JSONObject
+import org.matrix.android.sdk.api.extensions.tryOrNull
+import org.matrix.android.sdk.api.failure.MatrixError
import timber.log.Timber
typealias Content = JsonDict
@@ -90,6 +92,16 @@ data class Event(
@Transient
var sendState: SendState = SendState.UNKNOWN
+ @Transient
+ var sendStateDetails: String? = null
+
+ fun sendStateError(): MatrixError? {
+ return sendStateDetails?.let {
+ val matrixErrorAdapter = MoshiProvider.providesMoshi().adapter(MatrixError::class.java)
+ tryOrNull { matrixErrorAdapter.fromJson(it) }
+ }
+ }
+
/**
* The `age` value transcoded in a timestamp based on the device clock when the SDK received
* the event from the home server.
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 905e18b8e8..9c3fdd57da 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
@@ -31,9 +31,7 @@ object EventType {
const val TYPING = "m.typing"
const val REDACTION = "m.room.redaction"
const val RECEIPT = "m.receipt"
- const val TAG = "m.tag"
const val ROOM_KEY = "m.room_key"
- const val FULLY_READ = "m.fully_read"
const val PLUMBING = "m.room.plumbing"
const val BOT_OPTIONS = "m.room.bot.options"
const val PREVIEW_URLS = "org.matrix.room.preview_urls"
@@ -52,6 +50,10 @@ object EventType {
const val STATE_ROOM_GUEST_ACCESS = "m.room.guest_access"
const val STATE_ROOM_POWER_LEVELS = "m.room.power_levels"
+ const val STATE_SPACE_CHILD = "m.space.child"
+
+ const val STATE_SPACE_PARENT = "m.space.parent"
+
/**
* Note that this Event has been deprecated, see
* - https://matrix.org/docs/spec/client_server/r0.6.1#historical-events
@@ -74,6 +76,9 @@ object EventType {
const val CALL_NEGOTIATE = "m.call.negotiate"
const val CALL_REJECT = "m.call.reject"
const val CALL_HANGUP = "m.call.hangup"
+ const val CALL_ASSERTED_IDENTITY = "m.call.asserted_identity"
+ const val CALL_ASSERTED_IDENTITY_PREFIX = "org.matrix.call.asserted_identity"
+
// This type is not processed by the client, just sent to the server
const val CALL_REPLACES = "m.call.replaces"
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/file/FileService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/file/FileService.kt
index adfdc2498e..23dc1e0ba8 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/file/FileService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/file/FileService.kt
@@ -29,14 +29,19 @@ import java.io.File
*/
interface FileService {
- enum class FileState {
- IN_CACHE,
- DOWNLOADING,
- UNKNOWN
+ sealed class FileState {
+ /**
+ * The original file is in cache, but the decrypted files can be deleted for security reason.
+ * To decrypt the file again, call [downloadFile], the encrypted file will not be downloaded again
+ * @param decryptedFileInCache true if the decrypted file is available. Always true for clear files.
+ */
+ data class InCache(val decryptedFileInCache: Boolean) : FileState()
+ object Downloading : FileState()
+ object Unknown : FileState()
}
/**
- * Download a file.
+ * Download a file if necessary and ensure that if the file is encrypted, the file is decrypted.
* Result will be a decrypted file, stored in the cache folder. url parameter will be used to create unique filename to avoid name collision.
*/
suspend fun downloadFile(fileName: String,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/identity/IdentityService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/identity/IdentityService.kt
index 8f8967e8fb..ae546b6cec 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/identity/IdentityService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/identity/IdentityService.kt
@@ -35,7 +35,7 @@ interface IdentityService {
/**
* Check if the identity server is valid
* See https://matrix.org/docs/spec/identity_service/latest#status-check
- * RiotX SDK only supports identity server API v2
+ * Matrix Android SDK2 only supports identity server API v2
*/
suspend fun isValidIdentityServer(url: String)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/openid/OpenIdService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/openid/OpenIdService.kt
new file mode 100644
index 0000000000..65f6214f93
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/openid/OpenIdService.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2021 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.api.session.openid
+
+interface OpenIdService {
+
+ /**
+ * Gets an OpenID token object that the requester may supply to another service to verify their identity in Matrix.
+ * The generated token is only valid for exchanging for user information from the federation API for OpenID.
+ */
+ suspend fun getOpenIdToken(): OpenIdToken
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/openid/OpenIdToken.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/openid/OpenIdToken.kt
new file mode 100644
index 0000000000..2c2ea65681
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/openid/OpenIdToken.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2021 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.api.session.openid
+
+import com.squareup.moshi.Json
+import com.squareup.moshi.JsonClass
+
+@JsonClass(generateAdapter = true)
+data class OpenIdToken(
+ /**
+ * Required. An access token the consumer may use to verify the identity of the person who generated the token.
+ * This is given to the federation API GET /openid/userinfo to verify the user's identity.
+ */
+ @Json(name = "access_token")
+ val accessToken: String,
+
+ /**
+ * Required. The string "Bearer".
+ */
+ @Json(name = "token_type")
+ val tokenType: String,
+
+ /**
+ * Required. The homeserver domain the consumer should use when attempting to verify the user's identity.
+ */
+ @Json(name = "matrix_server_name")
+ val matrixServerName: String,
+
+ /**
+ * Required. The number of seconds before this token expires and a new one must be generated.
+ */
+ @Json(name = "expires_in")
+ val expiresIn: Int
+)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkService.kt
index ac1d726d03..a6d4583c76 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkService.kt
@@ -54,7 +54,7 @@ interface PermalinkService {
*
* @return the permalink, or null in case of error
*/
- fun createRoomPermalink(roomId: String): String?
+ fun createRoomPermalink(roomId: String, viaServers: List? = null): String?
/**
* Creates a permalink for an event. If you have an event you can use [createPermalink]
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/profile/ProfileService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/profile/ProfileService.kt
index e493adeaf2..05fa24946a 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/profile/ProfileService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/profile/ProfileService.kt
@@ -66,6 +66,7 @@ interface ProfileService {
/**
* Get the combined profile information for this user.
* This may return keys which are not limited to displayname or avatar_url.
+ * If server is configured as limit_profile_requests_to_users_who_share_rooms: true then response can be HTTP 403.
* @param userId the userId param to look for
*
*/
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushers/PushersService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushers/PushersService.kt
index 9ea820f5b3..a5ec100f64 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushers/PushersService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushers/PushersService.kt
@@ -66,12 +66,13 @@ interface PushersService {
/**
* Directly ask the push gateway to send a push to this device
+ * If successful, the push gateway has accepted the request. In this case, the app should receive a Push with the provided eventId.
+ * In case of error, PusherRejected will be thrown. In this case it means that the pushkey is not valid.
+ *
* @param url the push gateway url (full path)
* @param appId the application id
* @param pushkey the FCM token
* @param eventId the eventId which will be sent in the Push message. Use a fake eventId.
- * @param callback callback to know if the push gateway has accepted the request. In this case, the app should receive a Push with the provided eventId.
- * In case of error, PusherRejected failure can happen. In this case it means that the pushkey is not valid.
*/
suspend fun testPush(url: String,
appId: String,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/Room.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/Room.kt
index 257c83564e..cb04b05a74 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/Room.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/Room.kt
@@ -17,6 +17,7 @@
package org.matrix.android.sdk.api.session.room
import androidx.lifecycle.LiveData
+import org.matrix.android.sdk.api.session.room.accountdata.RoomAccountDataService
import org.matrix.android.sdk.api.session.room.alias.AliasService
import org.matrix.android.sdk.api.session.room.call.RoomCallService
import org.matrix.android.sdk.api.session.room.crypto.RoomCryptoService
@@ -34,6 +35,7 @@ import org.matrix.android.sdk.api.session.room.timeline.TimelineService
import org.matrix.android.sdk.api.session.room.typing.TypingService
import org.matrix.android.sdk.api.session.room.uploads.UploadsService
import org.matrix.android.sdk.api.session.search.SearchResult
+import org.matrix.android.sdk.api.session.space.Space
import org.matrix.android.sdk.api.util.Optional
/**
@@ -54,7 +56,8 @@ interface Room :
RoomCallService,
RelationService,
RoomCryptoService,
- RoomPushRuleService {
+ RoomPushRuleService,
+ RoomAccountDataService {
/**
* The roomId of this room
@@ -82,13 +85,18 @@ interface Room :
* @param beforeLimit how many events before the result are returned.
* @param afterLimit how many events after the result are returned.
* @param includeProfile requests that the server returns the historic profile information for the users that sent the events that were returned.
- * @param callback Callback to get the search result
+ * @return The search result
*/
suspend fun search(searchTerm: String,
- nextBatch: String?,
- orderByRecent: Boolean,
- limit: Int,
- beforeLimit: Int,
- afterLimit: Int,
- includeProfile: Boolean): SearchResult
+ nextBatch: String?,
+ orderByRecent: Boolean,
+ limit: Int,
+ beforeLimit: Int,
+ afterLimit: Int,
+ includeProfile: Boolean): SearchResult
+
+ /**
+ * Use this room as a Space, if the type is correct.
+ */
+ fun asSpace(): Space?
}
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 22045366cb..871c5378a6 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
@@ -20,6 +20,7 @@ import androidx.lifecycle.LiveData
import androidx.paging.PagedList
import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
+import org.matrix.android.sdk.api.session.room.model.Membership
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.create.CreateRoomParams
@@ -177,13 +178,15 @@ interface RoomService {
* TODO Doc
*/
fun getPagedRoomSummariesLive(queryParams: RoomSummaryQueryParams,
- pagedListConfig: PagedList.Config = defaultPagedListConfig): LiveData>
+ pagedListConfig: PagedList.Config = defaultPagedListConfig,
+ sortOrder: RoomSortOrder = RoomSortOrder.ACTIVITY): LiveData>
/**
* TODO Doc
*/
fun getFilteredPagedRoomSummariesLive(queryParams: RoomSummaryQueryParams,
- pagedListConfig: PagedList.Config = defaultPagedListConfig): UpdatableFilterLivePageResult
+ pagedListConfig: PagedList.Config = defaultPagedListConfig,
+ sortOrder: RoomSortOrder = RoomSortOrder.ACTIVITY): UpdatableLivePageResult
/**
* TODO Doc
@@ -197,4 +200,12 @@ interface RoomService {
.setEnablePlaceholders(false)
.setPrefetchDistance(10)
.build()
+
+ fun getFlattenRoomSummaryChildrenOf(spaceId: String?, memberships: List = Membership.activeMemberships()) : List
+
+ /**
+ * Returns all the children of this space, as LiveData
+ */
+ fun getFlattenRoomSummaryChildrenOfLive(spaceId: String?,
+ memberships: List = Membership.activeMemberships()): LiveData>
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomSortOrder.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomSortOrder.kt
new file mode 100644
index 0000000000..36da242527
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomSortOrder.kt
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2021 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.api.session.room
+
+enum class RoomSortOrder {
+ NAME,
+ ACTIVITY,
+ NONE
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomSummaryQueryParams.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomSummaryQueryParams.kt
index 7e04ebb5f2..88ec2de768 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomSummaryQueryParams.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomSummaryQueryParams.kt
@@ -16,15 +16,35 @@
package org.matrix.android.sdk.api.session.room
+import org.matrix.android.sdk.api.query.ActiveSpaceFilter
import org.matrix.android.sdk.api.query.QueryStringValue
import org.matrix.android.sdk.api.query.RoomCategoryFilter
import org.matrix.android.sdk.api.query.RoomTagQueryFilter
import org.matrix.android.sdk.api.session.room.model.Membership
+import org.matrix.android.sdk.api.session.room.model.RoomType
+import org.matrix.android.sdk.api.session.space.SpaceSummaryQueryParams
fun roomSummaryQueryParams(init: (RoomSummaryQueryParams.Builder.() -> Unit) = {}): RoomSummaryQueryParams {
return RoomSummaryQueryParams.Builder().apply(init).build()
}
+fun spaceSummaryQueryParams(init: (RoomSummaryQueryParams.Builder.() -> Unit) = {}): SpaceSummaryQueryParams {
+ return RoomSummaryQueryParams.Builder()
+ .apply(init)
+ .apply {
+ includeType = listOf(RoomType.SPACE)
+ excludeType = null
+ roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
+ }
+ .build()
+}
+
+enum class RoomCategoryFilter {
+ ONLY_DM,
+ ONLY_ROOMS,
+ ALL
+}
+
/**
* This class can be used to filter room summaries to use with:
* [org.matrix.android.sdk.api.session.room.Room] and [org.matrix.android.sdk.api.session.room.RoomService]
@@ -35,7 +55,11 @@ data class RoomSummaryQueryParams(
val canonicalAlias: QueryStringValue,
val memberships: List,
val roomCategoryFilter: RoomCategoryFilter?,
- val roomTagQueryFilter: RoomTagQueryFilter?
+ val roomTagQueryFilter: RoomTagQueryFilter?,
+ val excludeType: List?,
+ val includeType: List?,
+ val activeSpaceFilter: ActiveSpaceFilter?,
+ var activeGroupId: String? = null
) {
class Builder {
@@ -46,6 +70,10 @@ data class RoomSummaryQueryParams(
var memberships: List = Membership.all()
var roomCategoryFilter: RoomCategoryFilter? = RoomCategoryFilter.ALL
var roomTagQueryFilter: RoomTagQueryFilter? = null
+ var excludeType: List? = listOf(RoomType.SPACE)
+ var includeType: List? = null
+ var activeSpaceFilter: ActiveSpaceFilter = ActiveSpaceFilter.None
+ var activeGroupId: String? = null
fun build() = RoomSummaryQueryParams(
roomId = roomId,
@@ -53,7 +81,11 @@ data class RoomSummaryQueryParams(
canonicalAlias = canonicalAlias,
memberships = memberships,
roomCategoryFilter = roomCategoryFilter,
- roomTagQueryFilter = roomTagQueryFilter
+ roomTagQueryFilter = roomTagQueryFilter,
+ excludeType = excludeType,
+ includeType = includeType,
+ activeSpaceFilter = activeSpaceFilter,
+ activeGroupId = activeGroupId
)
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/UpdatableFilterLivePageResult.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/UpdatableLivePageResult.kt
similarity index 72%
rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/UpdatableFilterLivePageResult.kt
rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/UpdatableLivePageResult.kt
index 71b3c665e7..b83f57f5ef 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/UpdatableFilterLivePageResult.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/UpdatableLivePageResult.kt
@@ -20,8 +20,16 @@ import androidx.lifecycle.LiveData
import androidx.paging.PagedList
import org.matrix.android.sdk.api.session.room.model.RoomSummary
-interface UpdatableFilterLivePageResult {
+interface UpdatableLivePageResult {
val livePagedList: LiveData>
- fun updateQuery(queryParams: RoomSummaryQueryParams)
+ fun updateQuery(builder: (RoomSummaryQueryParams) -> RoomSummaryQueryParams)
+
+ val liveBoundaries: LiveData
}
+
+data class ResultBoundaries(
+ val frontLoaded: Boolean = false,
+ val endLoaded: Boolean = false,
+ val zeroItemLoaded: Boolean = false
+)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/accountdata/RoomAccountDataEvent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/accountdata/RoomAccountDataEvent.kt
new file mode 100644
index 0000000000..eb676ab5e7
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/accountdata/RoomAccountDataEvent.kt
@@ -0,0 +1,29 @@
+/*
+ * 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.room.accountdata
+
+import org.matrix.android.sdk.api.session.events.model.Content
+
+/**
+ * This is a simplified Event with just a roomId, a type and a content.
+ * Currently used types are defined in [RoomAccountDataTypes].
+ */
+data class RoomAccountDataEvent(
+ val roomId: String,
+ val type: String,
+ val content: Content
+)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/accountdata/AccountDataService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/accountdata/RoomAccountDataService.kt
similarity index 83%
rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/accountdata/AccountDataService.kt
rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/accountdata/RoomAccountDataService.kt
index 5ebeaad3de..190749c85c 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/accountdata/AccountDataService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/accountdata/RoomAccountDataService.kt
@@ -14,34 +14,37 @@
* limitations under the License.
*/
-package org.matrix.android.sdk.api.session.accountdata
+package org.matrix.android.sdk.api.session.room.accountdata
import androidx.lifecycle.LiveData
import org.matrix.android.sdk.api.session.events.model.Content
import org.matrix.android.sdk.api.util.Optional
-interface AccountDataService {
+/**
+ * This service is attached to a single room.
+ */
+interface RoomAccountDataService {
/**
* Retrieve the account data with the provided type or null if not found
*/
- fun getAccountDataEvent(type: String): UserAccountDataEvent?
+ fun getAccountDataEvent(type: String): RoomAccountDataEvent?
/**
* Observe the account data with the provided type
*/
- fun getLiveAccountDataEvent(type: String): LiveData>
+ fun getLiveAccountDataEvent(type: String): LiveData>
/**
* Retrieve the account data with the provided types. The return list can have a different size that
* the size of the types set, because some AccountData may not exist.
* If an empty set is provided, all the AccountData are retrieved
*/
- fun getAccountDataEvents(types: Set): List
+ fun getAccountDataEvents(types: Set): List
/**
* Observe the account data with the provided types. If an empty set is provided, all the AccountData are observed
*/
- fun getLiveAccountDataEvents(types: Set): LiveData>
+ fun getLiveAccountDataEvents(types: Set): LiveData>
/**
* Update the account data with the provided type and the provided account data content
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/accountdata/RoomAccountDataTypes.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/accountdata/RoomAccountDataTypes.kt
new file mode 100644
index 0000000000..0e80c307b4
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/accountdata/RoomAccountDataTypes.kt
@@ -0,0 +1,23 @@
+/*
+ * 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.room.accountdata
+
+object RoomAccountDataTypes {
+ const val EVENT_TYPE_VIRTUAL_ROOM = "im.vector.is_virtual_room"
+ const val EVENT_TYPE_TAG = "m.tag"
+ const val EVENT_TYPE_FULLY_READ = "m.fully_read"
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/alias/RoomAliasError.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/alias/RoomAliasError.kt
index d2cb7c58a9..1102eda11c 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/alias/RoomAliasError.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/alias/RoomAliasError.kt
@@ -17,7 +17,7 @@
package org.matrix.android.sdk.api.session.room.alias
sealed class RoomAliasError : Throwable() {
- object AliasEmpty : RoomAliasError()
+ object AliasIsBlank : RoomAliasError()
object AliasNotAvailable : RoomAliasError()
object AliasInvalid : RoomAliasError()
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/failure/CreateRoomFailure.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/failure/CreateRoomFailure.kt
index 208cdd4556..deab0ca3e7 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/failure/CreateRoomFailure.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/failure/CreateRoomFailure.kt
@@ -21,7 +21,7 @@ import org.matrix.android.sdk.api.failure.MatrixError
import org.matrix.android.sdk.api.session.room.alias.RoomAliasError
sealed class CreateRoomFailure : Failure.FeatureFailure() {
- object CreatedWithTimeout : CreateRoomFailure()
+ data class CreatedWithTimeout(val roomID: String) : CreateRoomFailure()
data class CreatedWithFederationFailure(val matrixError: MatrixError) : CreateRoomFailure()
data class AliasError(val aliasError: RoomAliasError) : CreateRoomFailure()
}
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 e778f5740d..5c46db7166 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
@@ -28,43 +28,43 @@ data class PowerLevelsContent(
/**
* The level required to ban a user. Defaults to 50 if unspecified.
*/
- @Json(name = "ban") val ban: Int = Role.Moderator.value,
+ @Json(name = "ban") val ban: Int? = null,
/**
* The level required to kick a user. Defaults to 50 if unspecified.
*/
- @Json(name = "kick") val kick: Int = Role.Moderator.value,
+ @Json(name = "kick") val kick: Int? = null,
/**
* The level required to invite a user. Defaults to 50 if unspecified.
*/
- @Json(name = "invite") val invite: Int = Role.Moderator.value,
+ @Json(name = "invite") val invite: Int? = null,
/**
* The level required to redact an event. Defaults to 50 if unspecified.
*/
- @Json(name = "redact") val redact: Int = Role.Moderator.value,
+ @Json(name = "redact") val redact: Int? = null,
/**
* The default level required to send message events. Can be overridden by the events key. Defaults to 0 if unspecified.
*/
- @Json(name = "events_default") val eventsDefault: Int = Role.Default.value,
+ @Json(name = "events_default") val eventsDefault: Int? = null,
/**
* The level required to send specific event types. This is a mapping from event type to power level required.
*/
- @Json(name = "events") val events: Map = emptyMap(),
+ @Json(name = "events") val events: Map? = null,
/**
* The default power level for every user in the room, unless their user_id is mentioned in the users key. Defaults to 0 if unspecified.
*/
- @Json(name = "users_default") val usersDefault: Int = Role.Default.value,
+ @Json(name = "users_default") val usersDefault: Int? = null,
/**
* The power levels for specific users. This is a mapping from user_id to power level for that user.
*/
- @Json(name = "users") val users: Map = emptyMap(),
+ @Json(name = "users") val users: Map? = null,
/**
* The default level required to send state events. Can be overridden by the events key. Defaults to 50 if unspecified.
*/
- @Json(name = "state_default") val stateDefault: Int = Role.Moderator.value,
+ @Json(name = "state_default") val stateDefault: Int? = null,
/**
* The power level requirements for specific notification types. This is a mapping from key to power level for that notifications key.
*/
- @Json(name = "notifications") val notifications: Map = emptyMap()
+ @Json(name = "notifications") val notifications: Map? = null
) {
/**
* Return a copy of this content with a new power level for the specified user
@@ -74,7 +74,7 @@ data class PowerLevelsContent(
*/
fun setUserPowerLevel(userId: String, powerLevel: Int?): PowerLevelsContent {
return copy(
- users = users.toMutableMap().apply {
+ users = users.orEmpty().toMutableMap().apply {
if (powerLevel == null || powerLevel == usersDefault) {
remove(userId)
} else {
@@ -91,7 +91,7 @@ data class PowerLevelsContent(
* @return the level, default to Moderator if the key is not found
*/
fun notificationLevel(key: String): Int {
- return when (val value = notifications[key]) {
+ return when (val value = notifications.orEmpty()[key]) {
// the first implementation was a string value
is String -> value.toInt()
is Double -> value.toInt()
@@ -107,3 +107,12 @@ data class PowerLevelsContent(
const val NOTIFICATIONS_ROOM_KEY = "room"
}
}
+
+// Fallback to default value, defined in the Matrix specification
+fun PowerLevelsContent.banOrDefault() = ban ?: Role.Moderator.value
+fun PowerLevelsContent.kickOrDefault() = kick ?: Role.Moderator.value
+fun PowerLevelsContent.inviteOrDefault() = invite ?: Role.Moderator.value
+fun PowerLevelsContent.redactOrDefault() = redact ?: Role.Moderator.value
+fun PowerLevelsContent.eventsDefaultOrDefault() = eventsDefault ?: Role.Default.value
+fun PowerLevelsContent.usersDefaultOrDefault() = usersDefault ?: Role.Default.value
+fun PowerLevelsContent.stateDefaultOrDefault() = stateDefault ?: 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 0760c6f1b4..020e7ed39e 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
@@ -40,7 +40,7 @@ data class RoomGuestAccessContent(
}
@JsonClass(generateAdapter = false)
-enum class GuestAccess {
- @Json(name = "can_join") CanJoin,
- @Json(name = "forbidden") Forbidden
+enum class GuestAccess(val value: String) {
+ @Json(name = "can_join") CanJoin("can_join"),
+ @Json(name = "forbidden") Forbidden("forbidden")
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomJoinRules.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomJoinRules.kt
index f3e8d357f3..a86301a276 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomJoinRules.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomJoinRules.kt
@@ -24,9 +24,10 @@ import com.squareup.moshi.JsonClass
* Enum for [RoomJoinRulesContent] : https://matrix.org/docs/spec/client_server/r0.4.0#m-room-join-rules
*/
@JsonClass(generateAdapter = false)
-enum class RoomJoinRules {
- @Json(name = "public") PUBLIC,
- @Json(name = "invite") INVITE,
- @Json(name = "knock") KNOCK,
- @Json(name = "private") PRIVATE
+enum class RoomJoinRules(val value: String) {
+ @Json(name = "public") PUBLIC("public"),
+ @Json(name = "invite") INVITE("invite"),
+ @Json(name = "knock") KNOCK("knock"),
+ @Json(name = "private") PRIVATE("private"),
+ @Json(name = "restricted") RESTRICTED("restricted")
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomJoinRulesAllowEntry.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomJoinRulesAllowEntry.kt
new file mode 100644
index 0000000000..7b87bc34d2
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomJoinRulesAllowEntry.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2021 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.matrix.android.sdk.api.session.room.model
+
+import com.squareup.moshi.Json
+import com.squareup.moshi.JsonClass
+
+@JsonClass(generateAdapter = true)
+data class RoomJoinRulesAllowEntry(
+ /**
+ * space: The room ID of the space to check the membership of.
+ */
+ @Json(name = "space") val spaceID: String,
+ /**
+ * via: A list of servers which may be used to peek for membership of the space.
+ */
+ @Json(name = "via") val via: List
+)
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 8082486b22..33f402cad3 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
@@ -1,5 +1,6 @@
/*
* Copyright 2020 The Matrix.org Foundation C.I.C.
+ * Copyright 2021 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,14 +27,19 @@ import timber.log.Timber
*/
@JsonClass(generateAdapter = true)
data class RoomJoinRulesContent(
- @Json(name = "join_rule") val _joinRules: String? = null
+ @Json(name = "join_rule") val _joinRules: String? = null,
+ /**
+ * If the allow key is an empty list (or not a list at all), then the room reverts to standard public join rules
+ */
+ @Json(name = "allow") val allowList: List? = null
) {
val joinRules: RoomJoinRules? = when (_joinRules) {
- "public" -> RoomJoinRules.PUBLIC
- "invite" -> RoomJoinRules.INVITE
- "knock" -> RoomJoinRules.KNOCK
+ "public" -> RoomJoinRules.PUBLIC
+ "invite" -> RoomJoinRules.INVITE
+ "knock" -> RoomJoinRules.KNOCK
"private" -> RoomJoinRules.PRIVATE
- else -> {
+ "restricted" -> RoomJoinRules.RESTRICTED
+ else -> {
Timber.w("Invalid value for RoomJoinRules: `$_joinRules`")
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 9455a83aff..cae4775e71 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
@@ -26,7 +26,7 @@ import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
* This class holds some data of a room.
* It can be retrieved by [org.matrix.android.sdk.api.session.room.Room] and [org.matrix.android.sdk.api.session.room.RoomService]
*/
-data class RoomSummary constructor(
+data class RoomSummary(
val roomId: String,
// Computed display name
val displayName: String = "",
@@ -35,7 +35,9 @@ data class RoomSummary constructor(
val avatarUrl: String = "",
val canonicalAlias: String? = null,
val aliases: List = emptyList(),
+ val joinRules: RoomJoinRules? = null,
val isDirect: Boolean = false,
+ val directUserId: String? = null,
val joinedMembersCount: Int? = 0,
val invitedMembersCount: Int? = 0,
val latestPreviewableEvent: TimelineEvent? = null,
@@ -54,7 +56,11 @@ data class RoomSummary constructor(
val inviterId: String? = null,
val breadcrumbsIndex: Int = NOT_IN_BREADCRUMBS,
val roomEncryptionTrustLevel: RoomEncryptionTrustLevel? = null,
- val hasFailedSending: Boolean = false
+ val hasFailedSending: Boolean = false,
+ val roomType: String? = null,
+ val spaceParents: List? = null,
+ val spaceChildren: List? = null,
+ val flattenParentIds: List = emptyList()
) {
val isVersioned: Boolean
@@ -69,6 +75,9 @@ data class RoomSummary constructor(
val isFavorite: Boolean
get() = hasTag(RoomTag.ROOM_TAG_FAVOURITE)
+ val isPublic: Boolean
+ get() = joinRules == RoomJoinRules.PUBLIC
+
fun hasTag(tag: String) = tags.any { it.name == tag }
val canStartCall: Boolean
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomThirdPartyInviteContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomThirdPartyInviteContent.kt
index 56503e3e35..a8a2cfb68b 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomThirdPartyInviteContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomThirdPartyInviteContent.kt
@@ -47,7 +47,7 @@ data class RoomThirdPartyInviteContent(
/**
* Keys with which the token may be signed.
*/
- @Json(name = "public_keys") val publicKeys: List? = emptyList()
+ @Json(name = "public_keys") val publicKeys: List?
)
@JsonClass(generateAdapter = true)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomType.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomType.kt
new file mode 100644
index 0000000000..b0f3a56d67
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomType.kt
@@ -0,0 +1,22 @@
+/*
+ * 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.room.model
+
+object RoomType {
+
+ const val SPACE = "m.space"
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/SpaceChildInfo.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/SpaceChildInfo.kt
new file mode 100644
index 0000000000..8cd2a0538d
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/SpaceChildInfo.kt
@@ -0,0 +1,38 @@
+/*
+ * 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.room.model
+
+data class SpaceChildInfo(
+ val childRoomId: String,
+ // We might not know this child at all,
+ // i.e we just know it exists but no info on type/name/etc..
+ val isKnown: Boolean,
+ val roomType: String?,
+ val name: String?,
+ val topic: String?,
+ val avatarUrl: String?,
+ val order: String?,
+ val activeMemberCount: Int?,
+ val autoJoin: Boolean,
+ val viaServers: List,
+ val parentRoomId: String?,
+ val suggested: Boolean?,
+ val canonicalAlias: String?,
+ val aliases: List?,
+ val worldReadable: Boolean
+
+)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/SpaceParentInfo.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/SpaceParentInfo.kt
new file mode 100644
index 0000000000..5ed81b0646
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/SpaceParentInfo.kt
@@ -0,0 +1,24 @@
+/*
+ * 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.room.model
+
+data class SpaceParentInfo(
+ val parentId: String?,
+ val roomSummary: RoomSummary?,
+ val canonical: Boolean?,
+ val viaServers: List
+)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallAnswerContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallAnswerContent.kt
index 45a54bb379..180b32db05 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallAnswerContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallAnswerContent.kt
@@ -44,7 +44,7 @@ data class CallAnswerContent(
* Capability advertisement.
*/
@Json(name = "capabilities") val capabilities: CallCapabilities? = null
-): CallSignallingContent {
+): CallSignalingContent {
@JsonClass(generateAdapter = true)
data class Answer(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallAssertedIdentityContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallAssertedIdentityContent.kt
new file mode 100644
index 0000000000..4c5413425f
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallAssertedIdentityContent.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2021 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.api.session.room.model.call
+
+import com.squareup.moshi.Json
+import com.squareup.moshi.JsonClass
+
+/**
+ * This event is sent by the callee when they wish to answer the call.
+ */
+@JsonClass(generateAdapter = true)
+data class CallAssertedIdentityContent(
+ /**
+ * Required. The ID of the call this event relates to.
+ */
+ @Json(name = "call_id") override val callId: String,
+ /**
+ * Required. ID to let user identify remote echo of their own events
+ */
+ @Json(name = "party_id") override val partyId: String? = null,
+ /**
+ * Required. The version of the VoIP specification this messages adheres to.
+ */
+ @Json(name = "version") override val version: String?,
+
+ /**
+ * Optional. Used to inform the transferee who they're now speaking to.
+ */
+ @Json(name = "asserted_identity") val assertedIdentity: AssertedIdentity? = null
+) : CallSignalingContent {
+
+ /**
+ * A user ID may be included if relevant, but unlike target_user, it is purely informational.
+ * The asserted identity may not represent a matrix user at all,
+ * in which case just a display_name may be given, or a perhaps a display_name and avatar_url.
+ */
+ @JsonClass(generateAdapter = true)
+ data class AssertedIdentity(
+ @Json(name = "id") val id: String? = null,
+ @Json(name = "display_name") val displayName: String? = null,
+ @Json(name = "avatar_url") val avatarUrl: String? = null
+ )
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallCandidatesContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallCandidatesContent.kt
index 7bfe7a97ac..dc0a1e3b2e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallCandidatesContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallCandidatesContent.kt
@@ -41,4 +41,4 @@ data class CallCandidatesContent(
* Required. The version of the VoIP specification this messages adheres to.
*/
@Json(name = "version") override val version: String?
-): CallSignallingContent
+): CallSignalingContent
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallHangupContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallHangupContent.kt
index 0acc409053..9d6e1a7eae 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallHangupContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallHangupContent.kt
@@ -44,7 +44,7 @@ data class CallHangupContent(
* One of: ["ice_failed", "invite_timeout"]
*/
@Json(name = "reason") val reason: Reason? = null
-) : CallSignallingContent {
+) : CallSignalingContent {
@JsonClass(generateAdapter = false)
enum class Reason {
@Json(name = "ice_failed")
@@ -56,6 +56,9 @@ data class CallHangupContent(
@Json(name = "user_hangup")
USER_HANGUP,
+ @Json(name = "replaced")
+ REPLACED,
+
@Json(name = "user_media_failed")
USER_MEDIA_FAILED,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallInviteContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallInviteContent.kt
index 42489bc0ce..e4332f0ea7 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallInviteContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallInviteContent.kt
@@ -55,7 +55,7 @@ data class CallInviteContent(
*/
@Json(name = "capabilities") val capabilities: CallCapabilities? = null
-): CallSignallingContent {
+): CallSignalingContent {
@JsonClass(generateAdapter = true)
data class Offer(
/**
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallNegotiateContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallNegotiateContent.kt
index 040993bb51..68dd5ef043 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallNegotiateContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallNegotiateContent.kt
@@ -47,7 +47,7 @@ data class CallNegotiateContent(
*/
@Json(name = "version") override val version: String?
- ): CallSignallingContent {
+ ): CallSignalingContent {
@JsonClass(generateAdapter = true)
data class Description(
/**
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallRejectContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallRejectContent.kt
index 1da229b179..ea412fbe3e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallRejectContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallRejectContent.kt
@@ -37,4 +37,4 @@ data class CallRejectContent(
* Required. The version of the VoIP specification this message adheres to.
*/
@Json(name = "version") override val version: String?
-) : CallSignallingContent
+) : CallSignalingContent
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallReplacesContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallReplacesContent.kt
index 97a3b8c7a7..4559c5db6d 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallReplacesContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallReplacesContent.kt
@@ -38,30 +38,30 @@ data class CallReplacesContent(
*/
@Json(name = "replacement_id") val replacementId: String? = null,
/**
- * Optional. If specified, the transferee client waits for an invite to this room and joins it
- * (possibly waiting for user confirmation) and then continues the transfer in this room.
- * If absent, the transferee contacts the Matrix User ID given in the target_user field in a room of its choosing.
+ * Optional. If specified, the transferee client waits for an invite to this room and joins it
+ * (possibly waiting for user confirmation) and then continues the transfer in this room.
+ * If absent, the transferee contacts the Matrix User ID given in the target_user field in a room of its choosing.
*/
- @Json(name = "target_room") val targerRoomId: String? = null,
+ @Json(name = "target_room") val targetRoomId: String? = null,
/**
- * An object giving information about the transfer target
+ * An object giving information about the transfer target
*/
@Json(name = "target_user") val targetUser: TargetUser? = null,
/**
- * If specified, gives the call ID for the transferee's client to use when placing the replacement call.
- * Mutually exclusive with await_call
+ * If specified, gives the call ID for the transferee's client to use when placing the replacement call.
+ * Mutually exclusive with await_call
*/
@Json(name = "create_call") val createCall: String? = null,
/**
- * If specified, gives the call ID that the transferee's client should wait for.
- * Mutually exclusive with create_call.
+ * If specified, gives the call ID that the transferee's client should wait for.
+ * Mutually exclusive with create_call.
*/
@Json(name = "await_call") val awaitCall: String? = null,
/**
* Required. The version of the VoIP specification this messages adheres to.
*/
@Json(name = "version") override val version: String?
-): CallSignallingContent {
+): CallSignalingContent {
@JsonClass(generateAdapter = true)
data class TargetUser(
@@ -77,6 +77,5 @@ data class CallReplacesContent(
* Optional. The avatar URL of the transfer target.
*/
@Json(name = "avatar_url") val avatarUrl: String?
-
)
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallSelectAnswerContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallSelectAnswerContent.kt
index 6ea70ac990..795f332711 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallSelectAnswerContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallSelectAnswerContent.kt
@@ -41,4 +41,4 @@ data class CallSelectAnswerContent(
* Required. The version of the VoIP specification this message adheres to.
*/
@Json(name = "version") override val version: String?
-): CallSignallingContent
+): CallSignalingContent
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallSignallingContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallSignalingContent.kt
similarity index 96%
rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallSignallingContent.kt
rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallSignalingContent.kt
index f8d8c2a5e8..92b43dd22c 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallSignallingContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallSignalingContent.kt
@@ -16,7 +16,7 @@
package org.matrix.android.sdk.api.session.room.model.call
-interface CallSignallingContent {
+interface CallSignalingContent {
/**
* Required. A unique identifier for the call.
*/
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/CreateRoomParams.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/CreateRoomParams.kt
index 80e3741a0c..ca8c66bb3b 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/CreateRoomParams.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/CreateRoomParams.kt
@@ -18,13 +18,15 @@ package org.matrix.android.sdk.api.session.room.model.create
import android.net.Uri
import org.matrix.android.sdk.api.session.identity.ThreePid
+import org.matrix.android.sdk.api.session.room.model.GuestAccess
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
import org.matrix.android.sdk.api.session.room.model.RoomDirectoryVisibility
import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibility
+import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesAllowEntry
import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM
// TODO Give a way to include other initial states
-class CreateRoomParams {
+open class CreateRoomParams {
/**
* A public visibility indicates that the room will be shown in the published room list.
* A private visibility will hide the room from the published room list.
@@ -68,6 +70,11 @@ class CreateRoomParams {
*/
val invite3pids = mutableListOf()
+ /**
+ * Initial Guest Access
+ */
+ var guestAccess: GuestAccess? = null
+
/**
* If set to true, when the room will be created, if cross-signing is enabled and we can get keys for every invited users,
* the encryption will be enabled on the created room
@@ -111,6 +118,17 @@ class CreateRoomParams {
}
}
+ var roomType: String? = null // RoomType.MESSAGING
+ set(value) {
+ field = value
+ if (value != null) {
+ creationContent[CREATION_CONTENT_KEY_ROOM_TYPE] = value
+ } else {
+ // This is the default value, we remove the field
+ creationContent.remove(CREATION_CONTENT_KEY_ROOM_TYPE)
+ }
+ }
+
/**
* The power level content to override in the default power level event
*/
@@ -136,7 +154,12 @@ class CreateRoomParams {
algorithm = MXCRYPTO_ALGORITHM_MEGOLM
}
+ var roomVersion: String? = null
+
+ var joinRuleRestricted: List? = null
+
companion object {
private const val CREATION_CONTENT_KEY_M_FEDERATE = "m.federate"
+ private const val CREATION_CONTENT_KEY_ROOM_TYPE = "type"
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/RoomCreateContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/RoomCreateContent.kt
index 0b595b1b2b..52e5c0e9c7 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/RoomCreateContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/RoomCreateContent.kt
@@ -26,5 +26,7 @@ import com.squareup.moshi.JsonClass
data class RoomCreateContent(
@Json(name = "creator") val creator: String? = null,
@Json(name = "room_version") val roomVersion: String? = null,
- @Json(name = "predecessor") val predecessor: Predecessor? = null
+ @Json(name = "predecessor") val predecessor: Predecessor? = null,
+ // Defines the room type, see #RoomType (user extensible)
+ @Json(name = "type") val type: String? = null
)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/FileInfo.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/FileInfo.kt
index e85bb0800a..f21074096e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/FileInfo.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/FileInfo.kt
@@ -47,3 +47,10 @@ data class FileInfo(
*/
@Json(name = "thumbnail_file") val thumbnailFile: EncryptedFileInfo? = null
)
+
+/**
+ * Get the url of the encrypted thumbnail or of the thumbnail
+ */
+fun FileInfo.getThumbnailUrl(): String? {
+ return thumbnailFile?.url ?: thumbnailUrl
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/ImageInfo.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/ImageInfo.kt
index 048febec39..c38ef5bc27 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/ImageInfo.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/ImageInfo.kt
@@ -40,7 +40,7 @@ data class ImageInfo(
/**
* Size of the image in bytes.
*/
- @Json(name = "size") val size: Int = 0,
+ @Json(name = "size") val size: Long = 0,
/**
* Metadata about the image referred to in thumbnail_url.
@@ -57,3 +57,10 @@ data class ImageInfo(
*/
@Json(name = "thumbnail_file") val thumbnailFile: EncryptedFileInfo? = null
)
+
+/**
+ * Get the url of the encrypted thumbnail or of the thumbnail
+ */
+fun ImageInfo.getThumbnailUrl(): String? {
+ return thumbnailFile?.url ?: thumbnailUrl
+}
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 a6908dce5b..a76c3c5b64 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
@@ -37,3 +37,10 @@ data class LocationInfo(
*/
@Json(name = "thumbnail_file") val thumbnailFile: EncryptedFileInfo? = null
)
+
+/**
+ * Get the url of the encrypted thumbnail or of the thumbnail
+ */
+fun LocationInfo.getThumbnailUrl(): String? {
+ return thumbnailFile?.url ?: thumbnailUrl
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageType.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageType.kt
index c96a800ee5..1e8959afc3 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageType.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageType.kt
@@ -35,5 +35,5 @@ object MessageType {
const val MSGTYPE_STICKER_LOCAL = "org.matrix.android.sdk.sticker"
const val MSGTYPE_CONFETTI = "nic.custom.confetti"
- const val MSGTYPE_SNOW = "io.element.effect.snowfall"
+ const val MSGTYPE_SNOWFALL = "io.element.effect.snowfall"
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/VideoInfo.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/VideoInfo.kt
index 8379ee9338..8a36c26313 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/VideoInfo.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/VideoInfo.kt
@@ -62,3 +62,10 @@ data class VideoInfo(
*/
@Json(name = "thumbnail_file") val thumbnailFile: EncryptedFileInfo? = null
)
+
+/**
+ * Get the url of the encrypted thumbnail or of the thumbnail
+ */
+fun VideoInfo.getThumbnailUrl(): String? {
+ return thumbnailFile?.url ?: thumbnailUrl
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/peeking/PeekResult.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/peeking/PeekResult.kt
index db70dadef3..b78cd5e032 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/peeking/PeekResult.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/peeking/PeekResult.kt
@@ -16,6 +16,8 @@
package org.matrix.android.sdk.api.session.room.peeking
+import org.matrix.android.sdk.api.util.MatrixItem
+
sealed class PeekResult {
data class Success(
val roomId: String,
@@ -24,7 +26,10 @@ sealed class PeekResult {
val topic: String?,
val avatarUrl: String?,
val numJoinedMembers: Int?,
- val viaServers: List
+ val roomType: String?,
+ val viaServers: List,
+ val someMembers: List?,
+ val isPublic: Boolean
) : PeekResult()
data class PeekingNotAllowed(
@@ -34,4 +39,6 @@ sealed class PeekResult {
) : PeekResult()
object UnknownAlias : PeekResult()
+
+ fun isSuccess() = this is Success
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/powerlevels/PowerLevelsHelper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/powerlevels/PowerLevelsHelper.kt
index 4f1253c6df..99139723a8 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/powerlevels/PowerLevelsHelper.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/powerlevels/PowerLevelsHelper.kt
@@ -18,6 +18,13 @@
package org.matrix.android.sdk.api.session.room.powerlevels
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
+import org.matrix.android.sdk.api.session.room.model.banOrDefault
+import org.matrix.android.sdk.api.session.room.model.eventsDefaultOrDefault
+import org.matrix.android.sdk.api.session.room.model.inviteOrDefault
+import org.matrix.android.sdk.api.session.room.model.kickOrDefault
+import org.matrix.android.sdk.api.session.room.model.redactOrDefault
+import org.matrix.android.sdk.api.session.room.model.stateDefaultOrDefault
+import org.matrix.android.sdk.api.session.room.model.usersDefaultOrDefault
/**
* This class is an helper around PowerLevelsContent.
@@ -31,9 +38,9 @@ class PowerLevelsHelper(private val powerLevelsContent: PowerLevelsContent) {
* @return the power level
*/
fun getUserPowerLevelValue(userId: String): Int {
- return powerLevelsContent.users.getOrElse(userId) {
- powerLevelsContent.usersDefault
- }
+ return powerLevelsContent.users
+ ?.get(userId)
+ ?: powerLevelsContent.usersDefaultOrDefault()
}
/**
@@ -45,7 +52,7 @@ class PowerLevelsHelper(private val powerLevelsContent: PowerLevelsContent) {
fun getUserRole(userId: String): Role {
val value = getUserPowerLevelValue(userId)
// I think we should use powerLevelsContent.usersDefault, but Ganfra told me that it was like that on riot-Web
- return Role.fromValue(value, powerLevelsContent.eventsDefault)
+ return Role.fromValue(value, powerLevelsContent.eventsDefaultOrDefault())
}
/**
@@ -59,11 +66,11 @@ class PowerLevelsHelper(private val powerLevelsContent: PowerLevelsContent) {
fun isUserAllowedToSend(userId: String, isState: Boolean, eventType: String?): Boolean {
return if (userId.isNotEmpty()) {
val powerLevel = getUserPowerLevelValue(userId)
- val minimumPowerLevel = powerLevelsContent.events[eventType]
+ val minimumPowerLevel = powerLevelsContent.events?.get(eventType)
?: if (isState) {
- powerLevelsContent.stateDefault
+ powerLevelsContent.stateDefaultOrDefault()
} else {
- powerLevelsContent.eventsDefault
+ powerLevelsContent.eventsDefaultOrDefault()
}
powerLevel >= minimumPowerLevel
} else false
@@ -76,7 +83,7 @@ class PowerLevelsHelper(private val powerLevelsContent: PowerLevelsContent) {
*/
fun isUserAbleToInvite(userId: String): Boolean {
val powerLevel = getUserPowerLevelValue(userId)
- return powerLevel >= powerLevelsContent.invite
+ return powerLevel >= powerLevelsContent.inviteOrDefault()
}
/**
@@ -86,7 +93,7 @@ class PowerLevelsHelper(private val powerLevelsContent: PowerLevelsContent) {
*/
fun isUserAbleToBan(userId: String): Boolean {
val powerLevel = getUserPowerLevelValue(userId)
- return powerLevel >= powerLevelsContent.ban
+ return powerLevel >= powerLevelsContent.banOrDefault()
}
/**
@@ -96,7 +103,7 @@ class PowerLevelsHelper(private val powerLevelsContent: PowerLevelsContent) {
*/
fun isUserAbleToKick(userId: String): Boolean {
val powerLevel = getUserPowerLevelValue(userId)
- return powerLevel >= powerLevelsContent.kick
+ return powerLevel >= powerLevelsContent.kickOrDefault()
}
/**
@@ -106,6 +113,6 @@ class PowerLevelsHelper(private val powerLevelsContent: PowerLevelsContent) {
*/
fun isUserAbleToRedact(userId: String): Boolean {
val powerLevel = getUserPowerLevelValue(userId)
- return powerLevel >= powerLevelsContent.redact
+ return powerLevel >= powerLevelsContent.redactOrDefault()
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/summary/RoomAggregateNotificationCount.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/summary/RoomAggregateNotificationCount.kt
index 066178b1ec..b3440059e8 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/summary/RoomAggregateNotificationCount.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/summary/RoomAggregateNotificationCount.kt
@@ -20,6 +20,6 @@ data class RoomAggregateNotificationCount(
val notificationCount: Int,
val highlightCount: Int
) {
- val totalCount = notificationCount + highlightCount
+ val totalCount = notificationCount
val isHighlight = highlightCount > 0
}
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 32f6b94cd8..4a6462477d 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
@@ -21,6 +21,7 @@ import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.events.model.RelationType
import org.matrix.android.sdk.api.session.events.model.getRelationContent
+import org.matrix.android.sdk.api.session.events.model.isEdition
import org.matrix.android.sdk.api.session.events.model.isReply
import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.room.model.EventAnnotationsSummary
@@ -151,6 +152,10 @@ fun TimelineEvent.isReply(): Boolean {
return root.isReply()
}
+fun TimelineEvent.isEdition(): Boolean {
+ return root.isEdition()
+}
+
fun TimelineEvent.getTextEditableContent(): String? {
val lastContent = getLastMessageContent()
return if (isReply()) {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/CreateSpaceParams.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/CreateSpaceParams.kt
new file mode 100644
index 0000000000..42e6584838
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/CreateSpaceParams.kt
@@ -0,0 +1,35 @@
+/*
+ * 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.space
+
+import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
+import org.matrix.android.sdk.api.session.room.model.RoomType
+import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
+
+class CreateSpaceParams : CreateRoomParams() {
+
+ init {
+ // Space-rooms are distinguished from regular messaging rooms by the m.room.type of m.space
+ roomType = RoomType.SPACE
+
+ // Space-rooms should be created with a power level for events_default of 100,
+ // to prevent the rooms accidentally/maliciously clogging up with messages from random members of the space.
+ powerLevelContentOverride = PowerLevelsContent(
+ eventsDefault = 100
+ )
+ }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/JoinSpaceResult.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/JoinSpaceResult.kt
new file mode 100644
index 0000000000..e8c69977c6
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/JoinSpaceResult.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2021 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.api.session.space
+
+sealed class JoinSpaceResult {
+ object Success : JoinSpaceResult()
+ data class Fail(val error: Throwable) : JoinSpaceResult()
+
+ /** Success fully joined the space, but failed to join all or some of it's rooms */
+ data class PartialSuccess(val failedRooms: Map) : JoinSpaceResult()
+
+ fun isSuccess() = this is Success || this is PartialSuccess
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/Space.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/Space.kt
new file mode 100644
index 0000000000..db25762c2f
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/Space.kt
@@ -0,0 +1,53 @@
+/*
+ * 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.space
+
+import org.matrix.android.sdk.api.session.room.Room
+import org.matrix.android.sdk.api.session.room.model.RoomSummary
+
+interface Space {
+
+ fun asRoom(): Room
+
+ val spaceId: String
+
+ suspend fun leave(reason: String? = null)
+
+ /**
+ * A current snapshot of [RoomSummary] associated with the space
+ */
+ fun spaceSummary(): RoomSummary?
+
+ suspend fun addChildren(roomId: String,
+ viaServers: List?,
+ order: String?,
+ autoJoin: Boolean = false,
+ suggested: Boolean? = false)
+
+ suspend fun removeChildren(roomId: String)
+
+ @Throws
+ suspend fun setChildrenOrder(roomId: String, order: String?)
+
+ @Throws
+ suspend fun setChildrenAutoJoin(roomId: String, autoJoin: Boolean)
+
+ @Throws
+ suspend fun setChildrenSuggested(roomId: String, suggested: Boolean)
+
+// fun getChildren() : List
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/SpaceService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/SpaceService.kt
new file mode 100644
index 0000000000..fedf38fe06
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/SpaceService.kt
@@ -0,0 +1,87 @@
+/*
+ * 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.space
+
+import android.net.Uri
+import androidx.lifecycle.LiveData
+import org.matrix.android.sdk.api.session.room.RoomSummaryQueryParams
+import org.matrix.android.sdk.api.session.room.model.RoomSummary
+import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo
+import org.matrix.android.sdk.internal.session.space.peeking.SpacePeekResult
+
+typealias SpaceSummaryQueryParams = RoomSummaryQueryParams
+
+interface SpaceService {
+
+ /**
+ * Create a space asynchronously
+ * @return the spaceId of the created space
+ */
+ suspend fun createSpace(params: CreateSpaceParams): String
+
+ /**
+ * Just a shortcut for space creation for ease of use
+ */
+ suspend fun createSpace(name: String, topic: String?, avatarUri: Uri?, isPublic: Boolean): String
+
+ /**
+ * Get a space from a roomId
+ * @param spaceId the roomId to look for.
+ * @return a space with spaceId or null if room type is not space
+ */
+ fun getSpace(spaceId: String): Space?
+
+ /**
+ * Try to resolve (peek) rooms and subspace in this space.
+ * Use this call get preview of children of this space, particularly useful to get a
+ * preview of rooms that you did not join yet.
+ */
+ suspend fun peekSpace(spaceId: String): SpacePeekResult
+
+ /**
+ * Get's information of a space by querying the server
+ */
+ suspend fun querySpaceChildren(spaceId: String,
+ suggestedOnly: Boolean? = null,
+ autoJoinedOnly: Boolean? = null): Pair>
+
+ /**
+ * Get a live list of space summaries. This list is refreshed as soon as the data changes.
+ * @return the [LiveData] of List[SpaceSummary]
+ */
+ fun getSpaceSummariesLive(queryParams: SpaceSummaryQueryParams): LiveData>
+
+ fun getSpaceSummaries(spaceSummaryQueryParams: SpaceSummaryQueryParams): List
+
+ suspend fun joinSpace(spaceIdOrAlias: String,
+ reason: String? = null,
+ viaServers: List = emptyList()): JoinSpaceResult
+
+ suspend fun rejectInvite(spaceId: String, reason: String?)
+
+// fun getSpaceParentsOfRoom(roomId: String) : List
+
+ /**
+ * Let this room declare that it has a parent.
+ * @param canonical true if it should be the main parent of this room
+ * In practice, well behaved rooms should only have one canonical parent, but given this is not enforced:
+ * if multiple are present the client should select the one with the lowest room ID, as determined via a lexicographic utf-8 ordering.
+ */
+ suspend fun setSpaceParent(childRoomId: String, parentSpaceId: String, canonical: Boolean, viaServers: List)
+
+ fun getRootSpaceSummaries(): List
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/model/SpaceChildContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/model/SpaceChildContent.kt
new file mode 100644
index 0000000000..0c33cfa1e6
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/model/SpaceChildContent.kt
@@ -0,0 +1,70 @@
+/*
+ * 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.space.model
+
+import com.squareup.moshi.Json
+import com.squareup.moshi.JsonClass
+
+/**
+ * "content": {
+ * "via": ["example.com"],
+ * "order": "abcd",
+ * "default": true
+ * }
+ */
+@JsonClass(generateAdapter = true)
+data class SpaceChildContent(
+ /**
+ * Key which gives a list of candidate servers that can be used to join the room
+ * Children where via is not present are ignored.
+ */
+ @Json(name = "via") val via: List? = null,
+ /**
+ * The order key is a string which is used to provide a default ordering of siblings in the room list.
+ * (Rooms are sorted based on a lexicographic ordering of order values; rooms with no order come last.
+ * orders which are not strings, or do not consist solely of ascii characters in the range \x20 (space) to \x7F (~),
+ * or consist of more than 50 characters, are forbidden and should be ignored if received.)
+ */
+ @Json(name = "order") val order: String? = null,
+ /**
+ * The auto_join flag on a child listing allows a space admin to list the sub-spaces and rooms in that space which should
+ * be automatically joined by members of that space.
+ * (This is not a force-join, which are descoped for a future MSC; the user can subsequently part these room if they desire.)
+ */
+ @Json(name = "auto_join") val autoJoin: Boolean? = false,
+
+ /**
+ * If `suggested` is set to `true`, that indicates that the child should be advertised to
+ * members of the space by the client. This could be done by showing them eagerly
+ * in the room list. This is should be ignored if `auto_join` is set to `true`.
+ */
+ @Json(name = "suggested") val suggested: Boolean? = false
+) {
+ /**
+ * Orders which are not strings, or do not consist solely of ascii characters in the range \x20 (space) to \x7F (~),
+ * or consist of more than 50 characters, are forbidden and should be ignored if received.)
+ */
+ fun validOrder(): String? {
+ return order
+ ?.takeIf { it.length <= 50 }
+ ?.takeIf { ORDER_VALID_CHAR_REGEX.matches(it) }
+ }
+
+ companion object {
+ private val ORDER_VALID_CHAR_REGEX = "[ -~]+".toRegex()
+ }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/model/SpaceParentContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/model/SpaceParentContent.kt
new file mode 100644
index 0000000000..871a494914
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/model/SpaceParentContent.kt
@@ -0,0 +1,48 @@
+/*
+ * 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.space.model
+
+import com.squareup.moshi.Json
+import com.squareup.moshi.JsonClass
+
+/**
+ * Rooms can claim parents via the m.space.parent state event.
+ * {
+ * "type": "m.space.parent",
+ * "state_key": "!space:example.com",
+ * "content": {
+ * "via": ["example.com"],
+ * "canonical": true,
+ * }
+ * }
+ */
+@JsonClass(generateAdapter = true)
+data class SpaceParentContent(
+ /**
+ * Key which gives a list of candidate servers that can be used to join the parent.
+ * Parents where via is not present are ignored.
+ */
+ @Json(name = "via") val via: List? = null,
+ /**
+ * Canonical determines whether this is the main parent for the space.
+ * When a user joins a room with a canonical parent, clients may switch to view the room
+ * in the context of that space, peeking into it in order to find other rooms and group them together.
+ * In practice, well behaved rooms should only have one canonical parent, but given this is not enforced:
+ * if multiple are present the client should select the one with the lowest room ID, as determined via a lexicographic utf-8 ordering.
+ */
+ @Json(name = "canonical") val canonical: Boolean? = false
+)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/thirdparty/model/ThirdPartyUser.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/thirdparty/model/ThirdPartyUser.kt
index d77dfcfe35..246813a524 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/thirdparty/model/ThirdPartyUser.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/thirdparty/model/ThirdPartyUser.kt
@@ -22,16 +22,16 @@ import org.matrix.android.sdk.api.util.JsonDict
@JsonClass(generateAdapter = true)
data class ThirdPartyUser(
- /*
- Required. A Matrix User ID represting a third party user.
+ /**
+ * Required. A Matrix User ID representing a third party user.
*/
@Json(name = "userid") val userId: String,
- /*
- Required. The protocol ID that the third party location is a part of.
+ /**
+ * Required. The protocol ID that the third party location is a part of.
*/
@Json(name = "protocol") val protocol: String,
- /*
- Required. Information used to identify this third party location.
+ /**
+ * Required. Information used to identify this third party location.
*/
@Json(name = "fields") val fields: JsonDict
)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/widgets/model/WidgetContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/widgets/model/WidgetContent.kt
index 2c4c03b7d4..7a4231c277 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/widgets/model/WidgetContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/widgets/model/WidgetContent.kt
@@ -20,6 +20,7 @@ import android.annotation.SuppressLint
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import org.matrix.android.sdk.api.util.JsonDict
+import org.matrix.android.sdk.internal.util.safeCapitalize
/**
* Ref: https://github.com/matrix-org/matrix-doc/issues/1236
@@ -39,6 +40,6 @@ data class WidgetContent(
@SuppressLint("DefaultLocale")
fun getHumanName(): String {
- return (name ?: type ?: "").capitalize()
+ return (name ?: type ?: "").safeCapitalize()
}
}
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 db229a6453..3d2773fb4b 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
@@ -20,6 +20,8 @@ import org.matrix.android.sdk.BuildConfig
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
+import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo
import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoom
import org.matrix.android.sdk.api.session.room.sender.SenderInfo
import org.matrix.android.sdk.api.session.user.model.User
@@ -37,6 +39,8 @@ sealed class MatrixItem(
init {
if (BuildConfig.DEBUG) checkId()
}
+
+ override fun updateAvatar(newAvatar: String?) = copy(avatarUrl = newAvatar)
}
data class EventItem(override val id: String,
@@ -46,6 +50,8 @@ sealed class MatrixItem(
init {
if (BuildConfig.DEBUG) checkId()
}
+
+ override fun updateAvatar(newAvatar: String?) = copy(avatarUrl = newAvatar)
}
data class RoomItem(override val id: String,
@@ -55,6 +61,19 @@ sealed class MatrixItem(
init {
if (BuildConfig.DEBUG) checkId()
}
+
+ override fun updateAvatar(newAvatar: String?) = copy(avatarUrl = newAvatar)
+ }
+
+ data class SpaceItem(override val id: String,
+ override val displayName: String? = null,
+ override val avatarUrl: String? = null)
+ : MatrixItem(id, displayName, avatarUrl) {
+ init {
+ if (BuildConfig.DEBUG) checkId()
+ }
+
+ override fun updateAvatar(newAvatar: String?) = copy(avatarUrl = newAvatar)
}
data class RoomAliasItem(override val id: String,
@@ -67,6 +86,8 @@ sealed class MatrixItem(
// Best name is the id, and we keep the displayName of the room for the case we need the first letter
override fun getBestName() = id
+
+ override fun updateAvatar(newAvatar: String?) = copy(avatarUrl = newAvatar)
}
data class GroupItem(override val id: String,
@@ -79,6 +100,8 @@ sealed class MatrixItem(
// Best name is the id, and we keep the displayName of the room for the case we need the first letter
override fun getBestName() = id
+
+ override fun updateAvatar(newAvatar: String?) = copy(avatarUrl = newAvatar)
}
open fun getBestName(): String {
@@ -91,12 +114,15 @@ sealed class MatrixItem(
}
}
+ abstract fun updateAvatar(newAvatar: String?): MatrixItem
+
/**
* Return the prefix as defined in the matrix spec (and not extracted from the id)
*/
fun getIdPrefix() = when (this) {
is UserItem -> '@'
is EventItem -> '$'
+ is SpaceItem,
is RoomItem -> '!'
is RoomAliasItem -> '#'
is GroupItem -> '+'
@@ -116,22 +142,22 @@ sealed class MatrixItem(
var first = dn[startIndex]
// LEFT-TO-RIGHT MARK
- if (dn.length >= 2 && 0x200e == first.toInt()) {
+ if (dn.length >= 2 && 0x200e == first.code) {
startIndex++
first = dn[startIndex]
}
// check if it’s the start of a surrogate pair
- if (first.toInt() in 0xD800..0xDBFF && dn.length > startIndex + 1) {
+ if (first.code in 0xD800..0xDBFF && dn.length > startIndex + 1) {
val second = dn[startIndex + 1]
- if (second.toInt() in 0xDC00..0xDFFF) {
+ if (second.code in 0xDC00..0xDFFF) {
length++
}
}
dn.substring(startIndex, startIndex + length)
}
- .toUpperCase(Locale.ROOT)
+ .uppercase(Locale.ROOT)
}
companion object {
@@ -147,7 +173,11 @@ fun User.toMatrixItem() = MatrixItem.UserItem(userId, displayName, avatarUrl)
fun GroupSummary.toMatrixItem() = MatrixItem.GroupItem(groupId, displayName, avatarUrl)
-fun RoomSummary.toMatrixItem() = MatrixItem.RoomItem(roomId, displayName, avatarUrl)
+fun RoomSummary.toMatrixItem() = if (roomType == RoomType.SPACE) {
+ MatrixItem.SpaceItem(roomId, displayName, avatarUrl)
+} else {
+ MatrixItem.RoomItem(roomId, displayName, avatarUrl)
+}
fun RoomSummary.toRoomAliasMatrixItem() = MatrixItem.RoomAliasItem(canonicalAlias ?: roomId, displayName, avatarUrl)
@@ -157,3 +187,9 @@ fun PublicRoom.toMatrixItem() = MatrixItem.RoomItem(roomId, name ?: getPrimaryAl
fun RoomMemberSummary.toMatrixItem() = MatrixItem.UserItem(userId, displayName, avatarUrl)
fun SenderInfo.toMatrixItem() = MatrixItem.UserItem(userId, disambiguatedDisplayName, avatarUrl)
+
+fun SpaceChildInfo.toMatrixItem() = if (roomType == RoomType.SPACE) {
+ MatrixItem.SpaceItem(childRoomId, name ?: canonicalAlias, avatarUrl)
+} else {
+ MatrixItem.RoomItem(childRoomId, name ?: canonicalAlias, avatarUrl)
+}
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 c74999b4ab..182b37f2ad 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
@@ -22,6 +22,7 @@ import org.matrix.android.sdk.api.extensions.orFalse
object MimeTypes {
const val Any: String = "*/*"
const val OctetStream = "application/octet-stream"
+ const val Apk = "application/vnd.android.package-archive"
const val Images = "image/*"
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 441232f57f..c746ad863a 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
@@ -51,7 +51,7 @@ internal class SessionManager @Inject constructor(private val matrixComponent: M
}
}
- private fun getOrCreateSessionComponent(sessionParams: SessionParams): SessionComponent {
+ fun getOrCreateSessionComponent(sessionParams: SessionParams): SessionComponent {
return sessionComponents.getOrPut(sessionParams.credentials.sessionId()) {
DaggerSessionComponent
.factory()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/AuthAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/AuthAPI.kt
index f93f285c6e..5a9fa9edf6 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/AuthAPI.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/AuthAPI.kt
@@ -17,6 +17,7 @@
package org.matrix.android.sdk.internal.auth
import org.matrix.android.sdk.api.auth.data.Credentials
+import org.matrix.android.sdk.api.util.JsonDict
import org.matrix.android.sdk.internal.auth.data.Availability
import org.matrix.android.sdk.internal.auth.data.LoginFlowResponse
import org.matrix.android.sdk.internal.auth.data.PasswordLoginParams
@@ -73,6 +74,15 @@ internal interface AuthAPI {
@GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "register/available")
suspend fun registerAvailable(@Query("username") username: String): Availability
+ /**
+ * Get the combined profile information for this user.
+ * This API may be used to fetch the user's own profile information or other users; either locally or on remote homeservers.
+ * This API may return keys which are not limited to displayname or avatar_url.
+ * @param userId the user id to fetch profile info
+ */
+ @GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "profile/{userId}")
+ suspend fun getProfile(@Path("userId") userId: String): JsonDict
+
/**
* Add 3Pid during registration
* Ref: https://gist.github.com/jryans/839a09bf0c5a70e2f36ed990d50ed928
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/Constants.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/Constants.kt
index e0c52cf9ca..3742a429d2 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/Constants.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/Constants.kt
@@ -33,7 +33,6 @@ internal const val REGISTER_FALLBACK_PATH = "/_matrix/static/client/register/"
* Ref: https://matrix.org/docs/spec/client_server/latest#sso-client-login
*/
internal const val SSO_REDIRECT_PATH = "/_matrix/client/r0/login/sso/redirect"
-internal const val MSC2858_SSO_REDIRECT_PATH = "/_matrix/client/unstable/org.matrix.msc2858/login/sso/redirect"
internal const val SSO_REDIRECT_URL_PARAM = "redirectUrl"
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 46256f4b81..20ce438d8e 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
@@ -88,11 +88,9 @@ internal class DefaultAuthenticationService @Inject constructor(
return buildString {
append(homeServerUrlBase)
+ append(SSO_REDIRECT_PATH)
if (providerId != null) {
- append(MSC2858_SSO_REDIRECT_PATH)
append("/$providerId")
- } else {
- append(SSO_REDIRECT_PATH)
}
// Set the redirect url
appendParamToUrl(SSO_REDIRECT_URL_PARAM, redirectUrl)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/LoginFlowResponse.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/LoginFlowResponse.kt
index d0d17e2cd5..c718fae390 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/LoginFlowResponse.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/LoginFlowResponse.kt
@@ -42,7 +42,7 @@ internal data class LoginFlow(
* the client can show a button for each of the supported providers
* See MSC #2858
*/
- @Json(name = "org.matrix.msc2858.identity_providers")
+ @Json(name = "identity_providers")
val ssoIdentityProvider: List? = null
)
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 8b81f42e03..854caf8a62 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.login.LoginProfileInfo
import org.matrix.android.sdk.api.auth.login.LoginWizard
import org.matrix.android.sdk.api.auth.registration.RegisterThreePid
import org.matrix.android.sdk.api.session.Session
@@ -30,6 +31,7 @@ import org.matrix.android.sdk.internal.auth.db.PendingSessionData
import org.matrix.android.sdk.internal.auth.registration.AddThreePidRegistrationParams
import org.matrix.android.sdk.internal.auth.registration.RegisterAddThreePidTask
import org.matrix.android.sdk.internal.network.executeRequest
+import org.matrix.android.sdk.internal.session.content.DefaultContentUrlResolver
internal class DefaultLoginWizard(
private val authAPI: AuthAPI,
@@ -39,6 +41,15 @@ internal class DefaultLoginWizard(
private var pendingSessionData: PendingSessionData = pendingSessionStore.getPendingSessionData() ?: error("Pending session data should exist here")
+ private val getProfileTask: GetProfileTask = DefaultGetProfileTask(
+ authAPI,
+ DefaultContentUrlResolver(pendingSessionData.homeServerConnectionConfig)
+ )
+
+ override suspend fun getProfileInfo(matrixId: String): LoginProfileInfo {
+ return getProfileTask.execute(GetProfileTask.Params(matrixId))
+ }
+
override suspend fun login(login: String,
password: String,
deviceName: String): Session {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/GetProfileTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/GetProfileTask.kt
new file mode 100644
index 0000000000..bb9faf49c4
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/GetProfileTask.kt
@@ -0,0 +1,48 @@
+/*
+ * 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.internal.auth.login
+
+import org.matrix.android.sdk.api.auth.login.LoginProfileInfo
+import org.matrix.android.sdk.api.session.content.ContentUrlResolver
+import org.matrix.android.sdk.api.session.profile.ProfileService
+import org.matrix.android.sdk.internal.auth.AuthAPI
+import org.matrix.android.sdk.internal.network.executeRequest
+import org.matrix.android.sdk.internal.task.Task
+
+internal interface GetProfileTask : Task {
+ data class Params(
+ val userId: String
+ )
+}
+
+internal class DefaultGetProfileTask(
+ private val authAPI: AuthAPI,
+ private val contentUrlResolver: ContentUrlResolver
+) : GetProfileTask {
+
+ override suspend fun execute(params: GetProfileTask.Params): LoginProfileInfo {
+ val info = executeRequest(null) {
+ authAPI.getProfile(params.userId)
+ }
+
+ return LoginProfileInfo(
+ matrixId = params.userId,
+ displayName = info[ProfileService.DISPLAY_NAME_KEY] as? String,
+ fullAvatarUrl = contentUrlResolver.resolveFullSize(info[ProfileService.AVATAR_URL_KEY] as? String)
+ )
+ }
+}
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 4a3d53a8fc..4a156e74cd 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
@@ -66,8 +66,8 @@ internal class DefaultRegistrationWizard(
return performRegistrationRequest(params)
}
- override suspend fun createAccount(userName: String,
- password: String,
+ override suspend fun createAccount(userName: String?,
+ password: String?,
initialDeviceDisplayName: String?): RegistrationResult {
val params = RegistrationParams(
username = userName,
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 fafd1c465b..c3971058d3 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
@@ -348,7 +348,7 @@ internal class DefaultCryptoService @Inject constructor(
cryptoStore.close()
}
- // Aways enabled on RiotX
+ // Always enabled on Matrix Android SDK2
override fun isCryptoEnabled() = true
/**
@@ -440,7 +440,7 @@ internal class DefaultCryptoService @Inject constructor(
val existingAlgorithm = cryptoStore.getRoomAlgorithm(roomId)
if (!existingAlgorithm.isNullOrEmpty() && existingAlgorithm != algorithm) {
- Timber.e("## CRYPTO | setEncryptionInRoom() : Ignoring m.room.encryption event which requests a change of config in $roomId")
+ Timber.e("## CRYPTO | setEncryptionInRoom() : Ignoring m.room.encryption event which requests a change of config in $roomId")
return false
}
@@ -522,7 +522,7 @@ internal class DefaultCryptoService @Inject constructor(
if (algorithm != null) {
val userIds = getRoomUserIds(roomId)
val t0 = System.currentTimeMillis()
- Timber.v("## CRYPTO | encryptEventContent() starts")
+ Timber.v("## CRYPTO | encryptEventContent() starts")
runCatching {
preshareRoomKey(roomId, userIds)
val content = encrypt(roomId, eventType, eventContent)
@@ -818,15 +818,11 @@ internal class DefaultCryptoService @Inject constructor(
* Export the crypto keys
*
* @param password the password
- * @param callback the exported keys
+ * @return the exported keys
*/
- override fun exportRoomKeys(password: String, callback: MatrixCallback) {
- cryptoCoroutineScope.launch(coroutineDispatchers.main) {
- runCatching {
- val iterationCount = max(10000, MXMegolmExportEncryption.DEFAULT_ITERATION_COUNT)
- olmMachine!!.exportKeys(password, iterationCount)
- }.foldToCallback(callback)
- }
+ override suspend fun exportRoomKeys(password: String): ByteArray {
+ val iterationCount = max(10000, MXMegolmExportEncryption.DEFAULT_ITERATION_COUNT)
+ return olmMachine!!.exportKeys(password, iterationCount)
}
/**
@@ -835,19 +831,12 @@ internal class DefaultCryptoService @Inject constructor(
* @param roomKeysAsArray the room keys as array.
* @param password the password
* @param progressListener the progress listener
- * @param callback the asynchronous callback.
+ * @return the result ImportRoomKeysResult
*/
- override fun importRoomKeys(roomKeysAsArray: ByteArray,
+ override suspend fun importRoomKeys(roomKeysAsArray: ByteArray,
password: String,
- progressListener: ProgressListener?,
- callback: MatrixCallback) {
- cryptoCoroutineScope.launch(coroutineDispatchers.main) {
- runCatching {
- withContext(coroutineDispatchers.crypto) {
- olmMachine!!.importKeys(roomKeysAsArray, password, progressListener)
- }
- }.foldToCallback(callback)
- }
+ progressListener: ProgressListener?): ImportRoomKeysResult {
+ return olmMachine!!.importKeys(roomKeysAsArray, password, progressListener)
}
/**
@@ -1045,12 +1034,12 @@ internal class DefaultCryptoService @Inject constructor(
override fun prepareToEncrypt(roomId: String, callback: MatrixCallback) {
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
- Timber.d("## CRYPTO | prepareToEncrypt() : Check room members up to date")
+ Timber.d("## CRYPTO | prepareToEncrypt() : Check room members up to date")
// Ensure to load all room members
try {
loadRoomMembersTask.execute(LoadRoomMembersTask.Params(roomId))
} catch (failure: Throwable) {
- Timber.e("## CRYPTO | prepareToEncrypt() : Failed to load room members")
+ Timber.e("## CRYPTO | prepareToEncrypt() : Failed to load room members")
callback.onFailure(failure)
return@launch
}
@@ -1061,7 +1050,7 @@ internal class DefaultCryptoService @Inject constructor(
if (algorithm == null) {
val reason = String.format(MXCryptoError.UNABLE_TO_ENCRYPT_REASON, MXCryptoError.NO_MORE_ALGORITHM_REASON)
- Timber.e("## CRYPTO | prepareToEncrypt() : $reason")
+ Timber.e("## CRYPTO | prepareToEncrypt() : $reason")
callback.onFailure(IllegalArgumentException("Missing algorithm"))
return@launch
}
@@ -1071,7 +1060,7 @@ internal class DefaultCryptoService @Inject constructor(
}.fold(
{ callback.onSuccess(Unit) },
{
- Timber.e("## CRYPTO | prepareToEncrypt() failed.")
+ Timber.e("## CRYPTO | prepareToEncrypt() failed.")
callback.onFailure(it)
}
)
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 e5f1c011f8..63f15aaf6e 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
@@ -111,7 +111,7 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
res = !notReadyToRetryHS.contains(userId.substringAfter(':'))
}
} catch (e: Exception) {
- Timber.e(e, "## CRYPTO | canRetryKeysDownload() failed")
+ Timber.e(e, "## CRYPTO | canRetryKeysDownload() failed")
}
}
@@ -150,7 +150,7 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
for (userId in userIds) {
if (!deviceTrackingStatuses.containsKey(userId) || TRACKING_STATUS_NOT_TRACKED == deviceTrackingStatuses[userId]) {
- Timber.v("## CRYPTO | startTrackingDeviceList() : Now tracking device list for $userId")
+ Timber.v("## CRYPTO | startTrackingDeviceList() : Now tracking device list for $userId")
deviceTrackingStatuses[userId] = TRACKING_STATUS_PENDING_DOWNLOAD
isUpdated = true
}
@@ -178,7 +178,7 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
for (userId in changed) {
if (deviceTrackingStatuses.containsKey(userId)) {
- Timber.v("## CRYPTO | handleDeviceListsChanges() : Marking device list outdated for $userId")
+ Timber.v("## CRYPTO | handleDeviceListsChanges() : Marking device list outdated for $userId")
deviceTrackingStatuses[userId] = TRACKING_STATUS_PENDING_DOWNLOAD
isUpdated = true
}
@@ -186,7 +186,7 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
for (userId in left) {
if (deviceTrackingStatuses.containsKey(userId)) {
- Timber.v("## CRYPTO | handleDeviceListsChanges() : No longer tracking device list for $userId")
+ Timber.v("## CRYPTO | handleDeviceListsChanges() : No longer tracking device list for $userId")
deviceTrackingStatuses[userId] = TRACKING_STATUS_NOT_TRACKED
isUpdated = true
}
@@ -276,7 +276,7 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
* @param forceDownload Always download the keys even if cached.
*/
suspend fun downloadKeys(userIds: List?, forceDownload: Boolean): MXUsersDevicesMap {
- Timber.v("## CRYPTO | downloadKeys() : forceDownload $forceDownload : $userIds")
+ Timber.v("## CRYPTO | downloadKeys() : forceDownload $forceDownload : $userIds")
// Map from userId -> deviceId -> MXDeviceInfo
val stored = MXUsersDevicesMap()
@@ -305,13 +305,13 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
}
}
return if (downloadUsers.isEmpty()) {
- Timber.v("## CRYPTO | downloadKeys() : no new user device")
+ Timber.v("## CRYPTO | downloadKeys() : no new user device")
stored
} else {
- Timber.v("## CRYPTO | downloadKeys() : starts")
+ Timber.v("## CRYPTO | downloadKeys() : starts")
val t0 = System.currentTimeMillis()
val result = doKeyDownloadForUsers(downloadUsers)
- Timber.v("## CRYPTO | downloadKeys() : doKeyDownloadForUsers succeeds after ${System.currentTimeMillis() - t0} ms")
+ Timber.v("## CRYPTO | downloadKeys() : doKeyDownloadForUsers succeeds after ${System.currentTimeMillis() - t0} ms")
result.also {
it.addEntriesFromMap(stored)
}
@@ -324,7 +324,7 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
* @param downloadUsers the user ids list
*/
private suspend fun doKeyDownloadForUsers(downloadUsers: List): MXUsersDevicesMap {
- Timber.v("## CRYPTO | doKeyDownloadForUsers() : doKeyDownloadForUsers ${downloadUsers.logLimit()}")
+ Timber.v("## CRYPTO | doKeyDownloadForUsers() : doKeyDownloadForUsers ${downloadUsers.logLimit()}")
// get the user ids which did not already trigger a keys download
val filteredUsers = downloadUsers.filter { MatrixPatterns.isUserId(it) }
if (filteredUsers.isEmpty()) {
@@ -335,16 +335,16 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
val response = try {
downloadKeysForUsersTask.execute(params)
} catch (throwable: Throwable) {
- Timber.e(throwable, "## CRYPTO | doKeyDownloadForUsers(): error")
+ Timber.e(throwable, "## CRYPTO | doKeyDownloadForUsers(): error")
onKeysDownloadFailed(filteredUsers)
throw throwable
}
- Timber.v("## CRYPTO | doKeyDownloadForUsers() : Got keys for " + filteredUsers.size + " users")
+ Timber.v("## CRYPTO | doKeyDownloadForUsers() : Got keys for " + filteredUsers.size + " users")
for (userId in filteredUsers) {
// al devices =
val models = response.deviceKeys?.get(userId)?.mapValues { entry -> CryptoInfoMapper.map(entry.value) }
- Timber.v("## CRYPTO | doKeyDownloadForUsers() : Got keys for $userId : $models")
+ Timber.v("## CRYPTO | doKeyDownloadForUsers() : Got keys for $userId : $models")
if (!models.isNullOrEmpty()) {
val workingCopy = models.toMutableMap()
for ((deviceId, deviceInfo) in models) {
@@ -377,13 +377,13 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
}
val masterKey = response.masterKeys?.get(userId)?.toCryptoModel().also {
- Timber.v("## CRYPTO | CrossSigning : Got keys for $userId : MSK ${it?.unpaddedBase64PublicKey}")
+ Timber.v("## CRYPTO | CrossSigning : Got keys for $userId : MSK ${it?.unpaddedBase64PublicKey}")
}
val selfSigningKey = response.selfSigningKeys?.get(userId)?.toCryptoModel()?.also {
- Timber.v("## CRYPTO | CrossSigning : Got keys for $userId : SSK ${it.unpaddedBase64PublicKey}")
+ Timber.v("## CRYPTO | CrossSigning : Got keys for $userId : SSK ${it.unpaddedBase64PublicKey}")
}
val userSigningKey = response.userSigningKeys?.get(userId)?.toCryptoModel()?.also {
- Timber.v("## CRYPTO | CrossSigning : Got keys for $userId : USK ${it.unpaddedBase64PublicKey}")
+ Timber.v("## CRYPTO | CrossSigning : Got keys for $userId : USK ${it.unpaddedBase64PublicKey}")
}
cryptoStore.storeUserCrossSigningKeys(
userId,
@@ -411,28 +411,28 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
*/
private fun validateDeviceKeys(deviceKeys: CryptoDeviceInfo?, userId: String, deviceId: String, previouslyStoredDeviceKeys: CryptoDeviceInfo?): Boolean {
if (null == deviceKeys) {
- Timber.e("## CRYPTO | validateDeviceKeys() : deviceKeys is null from $userId:$deviceId")
+ Timber.e("## CRYPTO | validateDeviceKeys() : deviceKeys is null from $userId:$deviceId")
return false
}
if (null == deviceKeys.keys) {
- Timber.e("## CRYPTO | validateDeviceKeys() : deviceKeys.keys is null from $userId:$deviceId")
+ Timber.e("## CRYPTO | validateDeviceKeys() : deviceKeys.keys is null from $userId:$deviceId")
return false
}
if (null == deviceKeys.signatures) {
- Timber.e("## CRYPTO | validateDeviceKeys() : deviceKeys.signatures is null from $userId:$deviceId")
+ Timber.e("## CRYPTO | validateDeviceKeys() : deviceKeys.signatures is null from $userId:$deviceId")
return false
}
// Check that the user_id and device_id in the received deviceKeys are correct
if (deviceKeys.userId != userId) {
- Timber.e("## CRYPTO | validateDeviceKeys() : Mismatched user_id ${deviceKeys.userId} from $userId:$deviceId")
+ Timber.e("## CRYPTO | validateDeviceKeys() : Mismatched user_id ${deviceKeys.userId} from $userId:$deviceId")
return false
}
if (deviceKeys.deviceId != deviceId) {
- Timber.e("## CRYPTO | validateDeviceKeys() : Mismatched device_id ${deviceKeys.deviceId} from $userId:$deviceId")
+ Timber.e("## CRYPTO | validateDeviceKeys() : Mismatched device_id ${deviceKeys.deviceId} from $userId:$deviceId")
return false
}
@@ -440,21 +440,21 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
val signKey = deviceKeys.keys[signKeyId]
if (null == signKey) {
- Timber.e("## CRYPTO | validateDeviceKeys() : Device $userId:${deviceKeys.deviceId} has no ed25519 key")
+ Timber.e("## CRYPTO | validateDeviceKeys() : Device $userId:${deviceKeys.deviceId} has no ed25519 key")
return false
}
val signatureMap = deviceKeys.signatures[userId]
if (null == signatureMap) {
- Timber.e("## CRYPTO | validateDeviceKeys() : Device $userId:${deviceKeys.deviceId} has no map for $userId")
+ Timber.e("## CRYPTO | validateDeviceKeys() : Device $userId:${deviceKeys.deviceId} has no map for $userId")
return false
}
val signature = signatureMap[signKeyId]
if (null == signature) {
- Timber.e("## CRYPTO | validateDeviceKeys() : Device $userId:${deviceKeys.deviceId} is not signed")
+ Timber.e("## CRYPTO | validateDeviceKeys() : Device $userId:${deviceKeys.deviceId} is not signed")
return false
}
@@ -469,7 +469,7 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
}
if (!isVerified) {
- Timber.e("## CRYPTO | validateDeviceKeys() : Unable to verify signature on device " + userId + ":"
+ Timber.e("## CRYPTO | validateDeviceKeys() : Unable to verify signature on device " + userId + ":"
+ deviceKeys.deviceId + " with error " + errorMessage)
return false
}
@@ -480,12 +480,12 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
// best off sticking with the original keys.
//
// Should we warn the user about it somehow?
- Timber.e("## CRYPTO | validateDeviceKeys() : WARNING:Ed25519 key for device " + userId + ":"
+ Timber.e("## CRYPTO | validateDeviceKeys() : WARNING:Ed25519 key for device " + userId + ":"
+ deviceKeys.deviceId + " has changed : "
+ previouslyStoredDeviceKeys.fingerprint() + " -> " + signKey)
- Timber.e("## CRYPTO | validateDeviceKeys() : $previouslyStoredDeviceKeys -> $deviceKeys")
- Timber.e("## CRYPTO | validateDeviceKeys() : ${previouslyStoredDeviceKeys.keys} -> ${deviceKeys.keys}")
+ Timber.e("## CRYPTO | validateDeviceKeys() : $previouslyStoredDeviceKeys -> $deviceKeys")
+ Timber.e("## CRYPTO | validateDeviceKeys() : ${previouslyStoredDeviceKeys.keys} -> ${deviceKeys.keys}")
return false
}
@@ -499,7 +499,7 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
* This method must be called on getEncryptingThreadHandler() thread.
*/
suspend fun refreshOutdatedDeviceLists() {
- Timber.v("## CRYPTO | refreshOutdatedDeviceLists()")
+ Timber.v("## CRYPTO | refreshOutdatedDeviceLists()")
val deviceTrackingStatuses = cryptoStore.getDeviceTrackingStatuses().toMutableMap()
val users = deviceTrackingStatuses.keys.filterTo(mutableListOf()) { userId ->
@@ -518,10 +518,10 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
doKeyDownloadForUsers(users)
}.fold(
{
- Timber.v("## CRYPTO | refreshOutdatedDeviceLists() : done")
+ Timber.v("## CRYPTO | refreshOutdatedDeviceLists() : done")
},
{
- Timber.e(it, "## CRYPTO | refreshOutdatedDeviceLists() : ERROR updating device keys for users $users")
+ Timber.e(it, "## CRYPTO | refreshOutdatedDeviceLists() : ERROR updating device keys for users $users")
}
)
}
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 32324896fa..8d86380e39 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
@@ -92,20 +92,20 @@ internal class EventDecryptor @Inject constructor(
private fun internalDecryptEvent(event: Event, timeline: String): MXEventDecryptionResult {
val eventContent = event.content
if (eventContent == null) {
- Timber.e("## CRYPTO | decryptEvent : empty event content")
+ Timber.e("## CRYPTO | decryptEvent : empty event content")
throw MXCryptoError.Base(MXCryptoError.ErrorType.BAD_ENCRYPTED_MESSAGE, MXCryptoError.BAD_ENCRYPTED_MESSAGE_REASON)
} else {
val algorithm = eventContent["algorithm"]?.toString()
val alg = roomDecryptorProvider.getOrCreateRoomDecryptor(event.roomId, algorithm)
if (alg == null) {
val reason = String.format(MXCryptoError.UNABLE_TO_DECRYPT_REASON, event.eventId, algorithm)
- Timber.e("## CRYPTO | decryptEvent() : $reason")
+ Timber.e("## CRYPTO | decryptEvent() : $reason")
throw MXCryptoError.Base(MXCryptoError.ErrorType.UNABLE_TO_DECRYPT, reason)
} else {
try {
return alg.decryptEvent(event, timeline)
} catch (mxCryptoError: MXCryptoError) {
- Timber.v("## CRYPTO | internalDecryptEvent : Failed to decrypt ${event.eventId} reason: $mxCryptoError")
+ Timber.v("## CRYPTO | internalDecryptEvent : Failed to decrypt ${event.eventId} reason: $mxCryptoError")
if (algorithm == MXCRYPTO_ALGORITHM_OLM) {
if (mxCryptoError is MXCryptoError.Base
&& mxCryptoError.errorType == MXCryptoError.ErrorType.BAD_ENCRYPTED_MESSAGE) {
@@ -119,7 +119,7 @@ internal class EventDecryptor @Inject constructor(
markOlmSessionForUnwedging(event.senderId ?: "", it)
}
?: run {
- Timber.i("## CRYPTO | internalDecryptEvent() : Failed to find sender crypto device for unwedging")
+ Timber.i("## CRYPTO | internalDecryptEvent() : Failed to find sender crypto device for unwedging")
}
}
}
@@ -137,18 +137,18 @@ internal class EventDecryptor @Inject constructor(
val lastForcedDate = lastNewSessionForcedDates.getObject(senderId, deviceKey) ?: 0
val now = System.currentTimeMillis()
if (now - lastForcedDate < DefaultCryptoService.CRYPTO_MIN_FORCE_SESSION_PERIOD_MILLIS) {
- Timber.w("## CRYPTO | markOlmSessionForUnwedging: New session already forced with device at $lastForcedDate. Not forcing another")
+ Timber.w("## CRYPTO | markOlmSessionForUnwedging: New session already forced with device at $lastForcedDate. Not forcing another")
return
}
- Timber.i("## CRYPTO | markOlmSessionForUnwedging from $senderId:${deviceInfo.deviceId}")
+ Timber.i("## CRYPTO | markOlmSessionForUnwedging from $senderId:${deviceInfo.deviceId}")
lastNewSessionForcedDates.setObject(senderId, deviceKey, now)
// offload this from crypto thread (?)
cryptoCoroutineScope.launch(coroutineDispatchers.computation) {
val ensured = ensureOlmSessionsForDevicesAction.handle(mapOf(senderId to listOf(deviceInfo)), force = true)
- Timber.i("## CRYPTO | markOlmSessionForUnwedging() : ensureOlmSessionsForDevicesAction isEmpty:${ensured.isEmpty}")
+ Timber.i("## CRYPTO | markOlmSessionForUnwedging() : ensureOlmSessionsForDevicesAction isEmpty:${ensured.isEmpty}")
// Now send a blank message on that session so the other side knows about it.
// (The keyshare request is sent in the clear so that won't do)
@@ -161,13 +161,13 @@ internal class EventDecryptor @Inject constructor(
val encodedPayload = messageEncrypter.encryptMessage(payloadJson, listOf(deviceInfo))
val sendToDeviceMap = MXUsersDevicesMap()
sendToDeviceMap.setObject(senderId, deviceInfo.deviceId, encodedPayload)
- Timber.i("## CRYPTO | markOlmSessionForUnwedging() : sending dummy to $senderId:${deviceInfo.deviceId}")
+ Timber.i("## CRYPTO | markOlmSessionForUnwedging() : sending dummy to $senderId:${deviceInfo.deviceId}")
withContext(coroutineDispatchers.io) {
val sendToDeviceParams = SendToDeviceTask.Params(EventType.ENCRYPTED, sendToDeviceMap)
try {
sendToDeviceTask.execute(sendToDeviceParams)
} catch (failure: Throwable) {
- Timber.e(failure, "## CRYPTO | markOlmSessionForUnwedging() : failed to send dummy to $senderId:${deviceInfo.deviceId}")
+ Timber.e(failure, "## CRYPTO | markOlmSessionForUnwedging() : failed to send dummy to $senderId:${deviceInfo.deviceId}")
}
}
}
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 787d16defc..70d2022299 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
@@ -74,7 +74,7 @@ internal class MXMegolmDecryption(private val userId: String,
@Throws(MXCryptoError::class)
private fun decryptEvent(event: Event, timeline: String, requestKeysOnFail: Boolean): MXEventDecryptionResult {
- Timber.v("## CRYPTO | decryptEvent ${event.eventId} , requestKeysOnFail:$requestKeysOnFail")
+ Timber.v("## CRYPTO | decryptEvent ${event.eventId}, requestKeysOnFail:$requestKeysOnFail")
if (event.roomId.isNullOrBlank()) {
throw MXCryptoError.Base(MXCryptoError.ErrorType.MISSING_FIELDS, MXCryptoError.MISSING_FIELDS_REASON)
}
@@ -155,7 +155,7 @@ internal class MXMegolmDecryption(private val userId: String,
withHeldInfo.code?.value ?: "",
withHeldInfo.reason)
} else {
- // This is un-used in riotX SDK, not sure if needed
+ // This is un-used in Matrix Android SDK2, not sure if needed
// addEventToPendingList(event, timeline)
if (requestKeysOnFail) {
requestKeysForEvent(event, false)
@@ -360,7 +360,7 @@ internal class MXMegolmDecryption(private val userId: String,
},
{
// TODO
- Timber.e(it, "## CRYPTO | shareKeysWithDevice: failed to get session for request $body")
+ Timber.e(it, "## CRYPTO | shareKeysWithDevice: failed to get session for request $body")
}
)
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 697711d051..a756444475 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
@@ -80,9 +80,9 @@ internal class MXMegolmEncryption(
eventType: String,
userIds: List): Content {
val ts = System.currentTimeMillis()
- Timber.v("## CRYPTO | encryptEventContent : getDevicesInRoom")
+ Timber.v("## CRYPTO | encryptEventContent : getDevicesInRoom")
val devices = getDevicesInRoom(userIds)
- Timber.v("## CRYPTO | encryptEventContent ${System.currentTimeMillis() - ts}: getDevicesInRoom ${devices.allowedDevices.map}")
+ Timber.v("## CRYPTO | encryptEventContent ${System.currentTimeMillis() - ts}: getDevicesInRoom ${devices.allowedDevices.map}")
val outboundSession = ensureOutboundSession(devices.allowedDevices)
return encryptContent(outboundSession, eventType, eventContent)
@@ -91,7 +91,7 @@ internal class MXMegolmEncryption(
// annoyingly we have to serialize again the saved outbound session to store message index :/
// if not we would see duplicate message index errors
olmDevice.storeOutboundGroupSessionForRoom(roomId, outboundSession.sessionId)
- Timber.v("## CRYPTO | encryptEventContent: Finished in ${System.currentTimeMillis() - ts} millis")
+ Timber.v("## CRYPTO | encryptEventContent: Finished in ${System.currentTimeMillis() - ts} millis")
}
}
@@ -118,13 +118,13 @@ internal class MXMegolmEncryption(
override suspend fun preshareKey(userIds: List) {
val ts = System.currentTimeMillis()
- Timber.v("## CRYPTO | preshareKey : getDevicesInRoom")
+ Timber.v("## CRYPTO | preshareKey : getDevicesInRoom")
val devices = getDevicesInRoom(userIds)
val outboundSession = ensureOutboundSession(devices.allowedDevices)
notifyWithheldForSession(devices.withHeldDevices, outboundSession)
- Timber.v("## CRYPTO | preshareKey ${System.currentTimeMillis() - ts} millis")
+ Timber.v("## CRYPTO | preshareKey ${System.currentTimeMillis() - ts} millis")
}
/**
@@ -133,7 +133,7 @@ internal class MXMegolmEncryption(
* @return the session description
*/
private fun prepareNewSessionInRoom(): MXOutboundSessionInfo {
- Timber.v("## CRYPTO | prepareNewSessionInRoom() ")
+ Timber.v("## CRYPTO | prepareNewSessionInRoom() ")
val sessionId = olmDevice.createOutboundGroupSessionForRoom(roomId)
val keysClaimedMap = HashMap()
@@ -153,7 +153,7 @@ internal class MXMegolmEncryption(
* @param devicesInRoom the devices list
*/
private suspend fun ensureOutboundSession(devicesInRoom: MXUsersDevicesMap): MXOutboundSessionInfo {
- Timber.v("## CRYPTO | ensureOutboundSession start")
+ Timber.v("## CRYPTO | ensureOutboundSession start")
var session = outboundSession
if (session == null
// Need to make a brand new session?
@@ -190,7 +190,7 @@ internal class MXMegolmEncryption(
devicesByUsers: Map>) {
// nothing to send, the task is done
if (devicesByUsers.isEmpty()) {
- Timber.v("## CRYPTO | shareKey() : nothing more to do")
+ Timber.v("## CRYPTO | shareKey() : nothing more to do")
return
}
// reduce the map size to avoid request timeout when there are too many devices (Users size * devices per user)
@@ -203,7 +203,7 @@ internal class MXMegolmEncryption(
break
}
}
- Timber.v("## CRYPTO | shareKey() ; sessionId<${session.sessionId}> userId ${subMap.keys}")
+ Timber.v("## CRYPTO | shareKey() ; sessionId<${session.sessionId}> userId ${subMap.keys}")
shareUserDevicesKey(session, subMap)
val remainingDevices = devicesByUsers - subMap.keys
shareKey(session, remainingDevices)
@@ -232,11 +232,11 @@ internal class MXMegolmEncryption(
payload["content"] = submap
var t0 = System.currentTimeMillis()
- Timber.v("## CRYPTO | shareUserDevicesKey() : starts")
+ Timber.v("## CRYPTO | shareUserDevicesKey() : starts")
val results = ensureOlmSessionsForDevicesAction.handle(devicesByUser)
Timber.v(
- """## CRYPTO | shareUserDevicesKey(): ensureOlmSessionsForDevices succeeds after ${System.currentTimeMillis() - t0} ms"""
+ """## CRYPTO | shareUserDevicesKey(): ensureOlmSessionsForDevices succeeds after ${System.currentTimeMillis() - t0} ms"""
.trimMargin()
)
val contentMap = MXUsersDevicesMap()
@@ -257,7 +257,7 @@ internal class MXMegolmEncryption(
noOlmToNotify.add(UserDevice(userId, deviceID))
continue
}
- Timber.i("## CRYPTO | shareUserDevicesKey() : Add to share keys contentMap for $userId:$deviceID")
+ Timber.i("## CRYPTO | shareUserDevicesKey() : Add to share keys contentMap for $userId:$deviceID")
contentMap.setObject(userId, deviceID, messageEncrypter.encryptMessage(payload, listOf(sessionResult.deviceInfo)))
haveTargets = true
}
@@ -289,17 +289,17 @@ internal class MXMegolmEncryption(
if (haveTargets) {
t0 = System.currentTimeMillis()
- Timber.i("## CRYPTO | shareUserDevicesKey() ${session.sessionId} : has target")
+ Timber.i("## CRYPTO | shareUserDevicesKey() ${session.sessionId} : has target")
val sendToDeviceParams = SendToDeviceTask.Params(EventType.ENCRYPTED, contentMap)
try {
sendToDeviceTask.execute(sendToDeviceParams)
- Timber.i("## CRYPTO | shareUserDevicesKey() : sendToDevice succeeds after ${System.currentTimeMillis() - t0} ms")
+ Timber.i("## CRYPTO | shareUserDevicesKey() : sendToDevice succeeds after ${System.currentTimeMillis() - t0} ms")
} catch (failure: Throwable) {
// What to do here...
- Timber.e("## CRYPTO | shareUserDevicesKey() : Failed to share session <${session.sessionId}> with $devicesByUser ")
+ Timber.e("## CRYPTO | shareUserDevicesKey() : Failed to share session <${session.sessionId}> with $devicesByUser ")
}
} else {
- Timber.i("## CRYPTO | shareUserDevicesKey() : no need to sharekey")
+ Timber.i("## CRYPTO | shareUserDevicesKey() : no need to sharekey")
}
if (noOlmToNotify.isNotEmpty()) {
@@ -317,7 +317,7 @@ internal class MXMegolmEncryption(
sessionId: String,
senderKey: String?,
code: WithHeldCode) {
- Timber.i("## CRYPTO | notifyKeyWithHeld() :sending withheld key for $targets session:$sessionId and code $code")
+ Timber.i("## CRYPTO | notifyKeyWithHeld() :sending withheld key for $targets session:$sessionId and code $code")
val withHeldContent = RoomKeyWithHeldContent(
roomId = roomId,
senderKey = senderKey,
@@ -336,7 +336,7 @@ internal class MXMegolmEncryption(
try {
sendToDeviceTask.execute(params)
} catch (failure: Throwable) {
- Timber.e("## CRYPTO | notifyKeyWithHeld() : Failed to notify withheld key for $targets session: $sessionId ")
+ Timber.e("## CRYPTO | notifyKeyWithHeld() : Failed to notify withheld key for $targets session: $sessionId ")
}
}
@@ -473,7 +473,7 @@ internal class MXMegolmEncryption(
val encodedPayload = messageEncrypter.encryptMessage(payloadJson, listOf(deviceInfo))
val sendToDeviceMap = MXUsersDevicesMap()
sendToDeviceMap.setObject(userId, deviceId, encodedPayload)
- Timber.i("## CRYPTO | reshareKey() : sending session $sessionId to $userId:$deviceId")
+ Timber.i("## CRYPTO | reshareKey() : sending session $sessionId to $userId:$deviceId")
val sendToDeviceParams = SendToDeviceTask.Params(EventType.ENCRYPTED, sendToDeviceMap)
return try {
sendToDeviceTask.execute(sendToDeviceParams)
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 1f80ce2c81..fb10cf4482 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
@@ -18,7 +18,7 @@ package org.matrix.android.sdk.internal.crypto.secrets
import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.listeners.ProgressListener
-import org.matrix.android.sdk.api.session.accountdata.AccountDataService
+import org.matrix.android.sdk.api.session.accountdata.SessionAccountDataService
import org.matrix.android.sdk.api.session.events.model.toContent
import org.matrix.android.sdk.api.session.securestorage.EncryptedSecretContent
import org.matrix.android.sdk.api.session.securestorage.IntegrityResult
@@ -56,7 +56,7 @@ import kotlin.experimental.and
internal class DefaultSharedSecretStorageService @Inject constructor(
@UserId private val userId: String,
- private val accountDataService: AccountDataService,
+ private val accountDataService: SessionAccountDataService,
private val outgoingGossipingRequestManager: OutgoingGossipingRequestManager,
private val coroutineDispatchers: MatrixCoroutineDispatchers,
private val cryptoCoroutineScope: CoroutineScope
@@ -84,7 +84,7 @@ internal class DefaultSharedSecretStorageService @Inject constructor(
)
} ?: storageKeyContent
- accountDataService.updateAccountData("$KEY_ID_BASE.$keyId", signedContent.toContent())
+ accountDataService.updateUserAccountData("$KEY_ID_BASE.$keyId", signedContent.toContent())
SsssKeyCreationInfo(
keyId = keyId,
content = storageKeyContent,
@@ -113,7 +113,7 @@ internal class DefaultSharedSecretStorageService @Inject constructor(
)
} ?: storageKeyContent
- accountDataService.updateAccountData(
+ accountDataService.updateUserAccountData(
"$KEY_ID_BASE.$keyId",
signedContent.toContent()
)
@@ -127,11 +127,11 @@ internal class DefaultSharedSecretStorageService @Inject constructor(
}
override fun hasKey(keyId: String): Boolean {
- return accountDataService.getAccountDataEvent("$KEY_ID_BASE.$keyId") != null
+ return accountDataService.getUserAccountDataEvent("$KEY_ID_BASE.$keyId") != null
}
override fun getKey(keyId: String): KeyInfoResult {
- val accountData = accountDataService.getAccountDataEvent("$KEY_ID_BASE.$keyId")
+ val accountData = accountDataService.getUserAccountDataEvent("$KEY_ID_BASE.$keyId")
?: return KeyInfoResult.Error(SharedSecretStorageError.UnknownKey(keyId))
return SecretStorageKeyContent.fromJson(accountData.content)?.let {
KeyInfoResult.Success(
@@ -143,14 +143,14 @@ internal class DefaultSharedSecretStorageService @Inject constructor(
override suspend fun setDefaultKey(keyId: String) {
val existingKey = getKey(keyId)
if (existingKey is KeyInfoResult.Success) {
- accountDataService.updateAccountData(DEFAULT_KEY_ID, mapOf("key" to keyId))
+ accountDataService.updateUserAccountData(DEFAULT_KEY_ID, mapOf("key" to keyId))
} else {
throw SharedSecretStorageError.UnknownKey(keyId)
}
}
override fun getDefaultKey(): KeyInfoResult {
- val accountData = accountDataService.getAccountDataEvent(DEFAULT_KEY_ID)
+ val accountData = accountDataService.getUserAccountDataEvent(DEFAULT_KEY_ID)
?: return KeyInfoResult.Error(SharedSecretStorageError.UnknownKey(DEFAULT_KEY_ID))
val keyId = accountData.content["key"] as? String
?: return KeyInfoResult.Error(SharedSecretStorageError.UnknownKey(DEFAULT_KEY_ID))
@@ -178,7 +178,7 @@ internal class DefaultSharedSecretStorageService @Inject constructor(
}
}
- accountDataService.updateAccountData(
+ accountDataService.updateUserAccountData(
type = name,
content = mapOf("encrypted" to encryptedContents)
)
@@ -288,7 +288,7 @@ internal class DefaultSharedSecretStorageService @Inject constructor(
}
override fun getAlgorithmsForSecret(name: String): List {
- val accountData = accountDataService.getAccountDataEvent(name)
+ val accountData = accountDataService.getUserAccountDataEvent(name)
?: return listOf(KeyInfoResult.Error(SharedSecretStorageError.UnknownSecret(name)))
val encryptedContent = accountData.content[ENCRYPTED] as? Map<*, *>
?: return listOf(KeyInfoResult.Error(SharedSecretStorageError.SecretNotEncrypted(name)))
@@ -303,7 +303,7 @@ internal class DefaultSharedSecretStorageService @Inject constructor(
}
override suspend fun getSecret(name: String, keyId: String?, secretKey: SsssKeySpec): String {
- val accountData = accountDataService.getAccountDataEvent(name) ?: throw SharedSecretStorageError.UnknownSecret(name)
+ val accountData = accountDataService.getUserAccountDataEvent(name) ?: throw SharedSecretStorageError.UnknownSecret(name)
val encryptedContent = accountData.content[ENCRYPTED] as? Map<*, *> ?: throw SharedSecretStorageError.SecretNotEncrypted(name)
val key = keyId?.let { getKey(it) } as? KeyInfoResult.Success ?: getDefaultKey() as? KeyInfoResult.Success
?: throw SharedSecretStorageError.UnknownKey(name)
@@ -368,7 +368,7 @@ internal class DefaultSharedSecretStorageService @Inject constructor(
}
secretNames.forEach { secretName ->
- val secretEvent = accountDataService.getAccountDataEvent(secretName)
+ val secretEvent = accountDataService.getUserAccountDataEvent(secretName)
?: return IntegrityResult.Error(SharedSecretStorageError.UnknownSecret(secretName))
if ((secretEvent.content["encrypted"] as? Map<*, *>)?.get(keyInfo.id) == null) {
return IntegrityResult.Error(SharedSecretStorageError.SecretNotEncryptedWithKey(secretName, keyInfo.id))
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SendVerificationMessageTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SendVerificationMessageTask.kt
index d8b9d3cd86..7fa48c3da1 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SendVerificationMessageTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SendVerificationMessageTask.kt
@@ -23,6 +23,7 @@ import org.matrix.android.sdk.internal.network.executeRequest
import org.matrix.android.sdk.internal.session.room.RoomAPI
import org.matrix.android.sdk.internal.session.room.send.LocalEchoRepository
import org.matrix.android.sdk.internal.task.Task
+import org.matrix.android.sdk.internal.util.toMatrixErrorStr
import javax.inject.Inject
internal interface SendVerificationMessageTask : Task {
@@ -55,7 +56,7 @@ internal class DefaultSendVerificationMessageTask @Inject constructor(
localEchoRepository.updateSendState(localId, event.roomId, SendState.SENT)
return response.eventId
} catch (e: Throwable) {
- localEchoRepository.updateSendState(localId, event.roomId, SendState.UNDELIVERED)
+ localEchoRepository.updateSendState(localId, event.roomId, SendState.UNDELIVERED, e.toMatrixErrorStr())
throw e
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tools/HkdfSha256.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tools/HkdfSha256.kt
index 6d52e682bc..6839ccd326 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tools/HkdfSha256.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tools/HkdfSha256.kt
@@ -57,7 +57,7 @@ object HkdfSha256 {
/*
The output OKM is calculated as follows:
- Notation | -> When the message is composed of several elements we use concatenation (denoted |) in the second argument;
+ Notation | -> When the message is composed of several elements we use concatenation (denoted |) in the second argument;
N = ceil(L/HashLen)
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 c7885ce449..4bf01a2809 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
@@ -345,7 +345,7 @@ internal abstract class SASDefaultVerificationTransaction(
}
protected fun hashUsingAgreedHashMethod(toHash: String): String? {
- if ("sha256" == accepted?.hash?.toLowerCase(Locale.ROOT)) {
+ if ("sha256" == accepted?.hash?.lowercase(Locale.ROOT)) {
val olmUtil = OlmUtility()
val hashBytes = olmUtil.sha256(toHash)
olmUtil.releaseUtility()
@@ -355,7 +355,7 @@ internal abstract class SASDefaultVerificationTransaction(
}
private fun macUsingAgreedMethod(message: String, info: String): String? {
- return when (accepted?.messageAuthenticationCode?.toLowerCase(Locale.ROOT)) {
+ return when (accepted?.messageAuthenticationCode?.lowercase(Locale.ROOT)) {
SAS_MAC_SHA256_LONGKDF -> getSAS().calculateMacLongKdf(message, info)
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/qrcode/Extensions.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/Extensions.kt
index 6bc3483e65..76e88442b6 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
@@ -48,7 +48,7 @@ fun QrCodeData.toEncodedString(): String {
// TransactionId
transactionId.forEach {
- result += it.toByte()
+ result += it.code.toByte()
}
// Keys
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/DatabaseCleaner.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/DatabaseCleaner.kt
index f11ecc5d75..ee58880eb8 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/DatabaseCleaner.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/DatabaseCleaner.kt
@@ -20,6 +20,7 @@ import io.realm.Realm
import io.realm.RealmConfiguration
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
+import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.internal.database.helper.nextDisplayIndex
import org.matrix.android.sdk.internal.database.model.ChunkEntity
import org.matrix.android.sdk.internal.database.model.ChunkEntityFields
@@ -29,7 +30,7 @@ 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.model.deleteOnCascade
import org.matrix.android.sdk.internal.di.SessionDatabase
-import org.matrix.android.sdk.internal.session.SessionLifecycleObserver
+import org.matrix.android.sdk.api.session.SessionLifecycleObserver
import org.matrix.android.sdk.internal.session.room.timeline.PaginationDirection
import org.matrix.android.sdk.internal.task.TaskExecutor
import timber.log.Timber
@@ -47,7 +48,7 @@ private const val MIN_NUMBER_OF_EVENTS_BY_CHUNK = 300
internal class DatabaseCleaner @Inject constructor(@SessionDatabase private val realmConfiguration: RealmConfiguration,
private val taskExecutor: TaskExecutor) : SessionLifecycleObserver {
- override fun onSessionStarted() {
+ override fun onSessionStarted(session: Session) {
taskExecutor.executorScope.launch(Dispatchers.Default) {
awaitTransaction(realmConfiguration) { realm ->
val allRooms = realm.where(RoomEntity::class.java).findAll()
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 0e3a7a2c49..d5ff7a0f84 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
@@ -71,7 +71,7 @@ internal class RealmKeysUtils @Inject constructor(context: Context,
val encodedKey = Base64.encodeToString(key, Base64.NO_PADDING)
val toStore = secretStoringUtils.securelyStoreString(encodedKey, alias)
sharedPreferences.edit {
- putString("${ENCRYPTED_KEY_PREFIX}_$alias", Base64.encodeToString(toStore!!, Base64.NO_PADDING))
+ putString("${ENCRYPTED_KEY_PREFIX}_$alias", Base64.encodeToString(toStore, Base64.NO_PADDING))
}
return key
}
@@ -84,7 +84,7 @@ internal class RealmKeysUtils @Inject constructor(context: Context,
val encryptedB64 = sharedPreferences.getString("${ENCRYPTED_KEY_PREFIX}_$alias", null)
val encryptedKey = Base64.decode(encryptedB64, Base64.NO_PADDING)
val b64 = secretStoringUtils.loadSecureSecret(encryptedKey, alias)
- return Base64.decode(b64!!, Base64.NO_PADDING)
+ return Base64.decode(b64, Base64.NO_PADDING)
}
fun configureEncryption(realmConfigurationBuilder: RealmConfiguration.Builder, alias: String) {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmLiveEntityObserver.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmLiveEntityObserver.kt
index 2a0cd963b2..c602ed7075 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmLiveEntityObserver.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmLiveEntityObserver.kt
@@ -17,7 +17,7 @@
package org.matrix.android.sdk.internal.database
import com.zhuinden.monarchy.Monarchy
-import org.matrix.android.sdk.internal.session.SessionLifecycleObserver
+import org.matrix.android.sdk.api.session.SessionLifecycleObserver
import org.matrix.android.sdk.internal.util.createBackgroundHandler
import io.realm.Realm
import io.realm.RealmChangeListener
@@ -28,6 +28,7 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.android.asCoroutineDispatcher
import kotlinx.coroutines.cancelChildren
+import org.matrix.android.sdk.api.session.Session
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicReference
@@ -46,7 +47,7 @@ internal abstract class RealmLiveEntityObserver(protected val r
private val backgroundRealm = AtomicReference()
private lateinit var results: AtomicReference>
- override fun onSessionStarted() {
+ override fun onSessionStarted(session: Session) {
if (isStarted.compareAndSet(false, true)) {
BACKGROUND_HANDLER.post {
val realm = Realm.getInstance(realmConfiguration)
@@ -58,7 +59,7 @@ internal abstract class RealmLiveEntityObserver(protected val r
}
}
- override fun onSessionStopped() {
+ override fun onSessionStopped(session: Session) {
if (isStarted.compareAndSet(true, false)) {
BACKGROUND_HANDLER.post {
results.getAndSet(null).removeAllChangeListeners()
@@ -70,7 +71,7 @@ internal abstract class RealmLiveEntityObserver(protected val r
}
}
- override fun onClearCache() {
+ override fun onClearCache(session: Session) {
observerScope.coroutineContext.cancelChildren()
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionProvider.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionProvider.kt
index f8d5d323a5..52fbabb49f 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionProvider.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionProvider.kt
@@ -20,8 +20,9 @@ import android.os.Looper
import androidx.annotation.MainThread
import com.zhuinden.monarchy.Monarchy
import io.realm.Realm
+import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.internal.di.SessionDatabase
-import org.matrix.android.sdk.internal.session.SessionLifecycleObserver
+import org.matrix.android.sdk.api.session.SessionLifecycleObserver
import org.matrix.android.sdk.internal.session.SessionScope
import javax.inject.Inject
import kotlin.concurrent.getOrSet
@@ -44,14 +45,14 @@ internal class RealmSessionProvider @Inject constructor(@SessionDatabase private
}
@MainThread
- override fun onSessionStarted() {
+ override fun onSessionStarted(session: Session) {
realmThreadLocal.getOrSet {
Realm.getInstance(monarchy.realmConfiguration)
}
}
@MainThread
- override fun onSessionStopped() {
+ override fun onSessionStopped(session: Session) {
realmThreadLocal.get()?.close()
realmThreadLocal.remove()
}
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 1daae906f2..2b3c3b28ee 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
@@ -19,25 +19,34 @@ package org.matrix.android.sdk.internal.database
import io.realm.DynamicRealm
import io.realm.FieldAttribute
import io.realm.RealmMigration
+import org.matrix.android.sdk.api.session.room.model.VersioningState
+import org.matrix.android.sdk.api.session.events.model.EventType
+import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesContent
+import org.matrix.android.sdk.api.session.room.model.create.RoomCreateContent
import org.matrix.android.sdk.api.session.room.model.tag.RoomTag
+import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntityFields
import org.matrix.android.sdk.internal.database.model.EditAggregatedSummaryEntityFields
import org.matrix.android.sdk.internal.database.model.EditionOfEventFields
import org.matrix.android.sdk.internal.database.model.EventEntityFields
import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEntityFields
import org.matrix.android.sdk.internal.database.model.PendingThreePidEntityFields
import org.matrix.android.sdk.internal.database.model.PreviewUrlCacheEntityFields
+import org.matrix.android.sdk.internal.database.model.RoomAccountDataEntityFields
import org.matrix.android.sdk.internal.database.model.RoomEntityFields
import org.matrix.android.sdk.internal.database.model.RoomMembersLoadStatusType
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields
import org.matrix.android.sdk.internal.database.model.RoomTagEntityFields
+import org.matrix.android.sdk.internal.database.model.SpaceChildSummaryEntityFields
+import org.matrix.android.sdk.internal.database.model.SpaceParentSummaryEntityFields
import org.matrix.android.sdk.internal.database.model.TimelineEventEntityFields
+import org.matrix.android.sdk.internal.di.MoshiProvider
import timber.log.Timber
import javax.inject.Inject
class RealmSessionStoreMigration @Inject constructor() : RealmMigration {
companion object {
- const val SESSION_STORE_SCHEMA_VERSION = 9L
+ const val SESSION_STORE_SCHEMA_VERSION = 14L
}
override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) {
@@ -52,6 +61,11 @@ class RealmSessionStoreMigration @Inject constructor() : RealmMigration {
if (oldVersion <= 6) migrateTo7(realm)
if (oldVersion <= 7) migrateTo8(realm)
if (oldVersion <= 8) migrateTo9(realm)
+ if (oldVersion <= 9) migrateTo10(realm)
+ if (oldVersion <= 10) migrateTo11(realm)
+ if (oldVersion <= 11) migrateTo12(realm)
+ if (oldVersion <= 12) migrateTo13(realm)
+ if (oldVersion <= 13) migrateTo14(realm)
}
private fun migrateTo1(realm: DynamicRealm) {
@@ -136,10 +150,6 @@ class RealmSessionStoreMigration @Inject constructor() : RealmMigration {
Timber.d("Step 7 -> 8")
val editionOfEventSchema = realm.schema.create("EditionOfEvent")
- .apply {
- // setEmbedded does not return `this`...
- isEmbedded = true
- }
.addField(EditionOfEventFields.CONTENT, String::class.java)
.addField(EditionOfEventFields.EVENT_ID, String::class.java)
.setRequired(EditionOfEventFields.EVENT_ID, true)
@@ -154,9 +164,13 @@ class RealmSessionStoreMigration @Inject constructor() : RealmMigration {
?.removeField("lastEditTs")
?.removeField("sourceLocalEchoEvents")
?.addRealmListField(EditAggregatedSummaryEntityFields.EDITIONS.`$`, editionOfEventSchema)
+
+ // This has to be done once a parent use the model as a child
+ // See https://github.com/realm/realm-java/issues/7402
+ editionOfEventSchema.isEmbedded = true
}
- fun migrateTo9(realm: DynamicRealm) {
+ private fun migrateTo9(realm: DynamicRealm) {
Timber.d("Step 8 -> 9")
realm.schema.get("RoomSummaryEntity")
@@ -174,7 +188,6 @@ class RealmSessionStoreMigration @Inject constructor() : RealmMigration {
?.addIndex(RoomSummaryEntityFields.IS_SERVER_NOTICE)
?.transform { obj ->
-
val isFavorite = obj.getList(RoomSummaryEntityFields.TAGS.`$`).any {
it.getString(RoomTagEntityFields.TAG_NAME) == RoomTag.ROOM_TAG_FAVOURITE
}
@@ -194,4 +207,103 @@ class RealmSessionStoreMigration @Inject constructor() : RealmMigration {
}
}
}
+
+ private fun migrateTo10(realm: DynamicRealm) {
+ Timber.d("Step 9 -> 10")
+ realm.schema.create("SpaceChildSummaryEntity")
+ ?.addField(SpaceChildSummaryEntityFields.ORDER, String::class.java)
+ ?.addField(SpaceChildSummaryEntityFields.CHILD_ROOM_ID, String::class.java)
+ ?.addField(SpaceChildSummaryEntityFields.AUTO_JOIN, Boolean::class.java)
+ ?.setNullable(SpaceChildSummaryEntityFields.AUTO_JOIN, true)
+ ?.addRealmObjectField(SpaceChildSummaryEntityFields.CHILD_SUMMARY_ENTITY.`$`, realm.schema.get("RoomSummaryEntity")!!)
+ ?.addRealmListField(SpaceChildSummaryEntityFields.VIA_SERVERS.`$`, String::class.java)
+
+ realm.schema.create("SpaceParentSummaryEntity")
+ ?.addField(SpaceParentSummaryEntityFields.PARENT_ROOM_ID, String::class.java)
+ ?.addField(SpaceParentSummaryEntityFields.CANONICAL, Boolean::class.java)
+ ?.setNullable(SpaceParentSummaryEntityFields.CANONICAL, true)
+ ?.addRealmObjectField(SpaceParentSummaryEntityFields.PARENT_SUMMARY_ENTITY.`$`, realm.schema.get("RoomSummaryEntity")!!)
+ ?.addRealmListField(SpaceParentSummaryEntityFields.VIA_SERVERS.`$`, String::class.java)
+
+ val creationContentAdapter = MoshiProvider.providesMoshi().adapter(RoomCreateContent::class.java)
+ 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)
+ ?.transform { obj ->
+
+ val creationEvent = realm.where("CurrentStateEventEntity")
+ .equalTo(CurrentStateEventEntityFields.ROOM_ID, obj.getString(RoomSummaryEntityFields.ROOM_ID))
+ .equalTo(CurrentStateEventEntityFields.TYPE, EventType.STATE_ROOM_CREATE)
+ .findFirst()
+
+ val roomType = creationEvent?.getObject(CurrentStateEventEntityFields.ROOT.`$`)
+ ?.getString(EventEntityFields.CONTENT)?.let {
+ creationContentAdapter.fromJson(it)?.type
+ }
+
+ obj.setString(RoomSummaryEntityFields.ROOM_TYPE, roomType)
+ }
+ ?.addRealmListField(RoomSummaryEntityFields.PARENTS.`$`, realm.schema.get("SpaceParentSummaryEntity")!!)
+ ?.addRealmListField(RoomSummaryEntityFields.CHILDREN.`$`, realm.schema.get("SpaceChildSummaryEntity")!!)
+ }
+
+ private fun migrateTo11(realm: DynamicRealm) {
+ Timber.d("Step 10 -> 11")
+ realm.schema.get("EventEntity")
+ ?.addField(EventEntityFields.SEND_STATE_DETAILS, String::class.java)
+ }
+
+ private fun migrateTo12(realm: DynamicRealm) {
+ Timber.d("Step 11 -> 12")
+
+ val joinRulesContentAdapter = MoshiProvider.providesMoshi().adapter(RoomJoinRulesContent::class.java)
+ realm.schema.get("RoomSummaryEntity")
+ ?.addField(RoomSummaryEntityFields.JOIN_RULES_STR, String::class.java)
+ ?.transform { obj ->
+ val joinRulesEvent = realm.where("CurrentStateEventEntity")
+ .equalTo(CurrentStateEventEntityFields.ROOM_ID, obj.getString(RoomSummaryEntityFields.ROOM_ID))
+ .equalTo(CurrentStateEventEntityFields.TYPE, EventType.STATE_ROOM_JOIN_RULES)
+ .findFirst()
+
+ val roomJoinRules = joinRulesEvent?.getObject(CurrentStateEventEntityFields.ROOT.`$`)
+ ?.getString(EventEntityFields.CONTENT)?.let {
+ joinRulesContentAdapter.fromJson(it)?.joinRules
+ }
+
+ obj.setString(RoomSummaryEntityFields.JOIN_RULES_STR, roomJoinRules?.name)
+ }
+
+ realm.schema.get("SpaceChildSummaryEntity")
+ ?.addField(SpaceChildSummaryEntityFields.SUGGESTED, Boolean::class.java)
+ ?.setNullable(SpaceChildSummaryEntityFields.SUGGESTED, true)
+ }
+
+ private fun migrateTo13(realm: DynamicRealm) {
+ Timber.d("Step 12 -> 13")
+ // Fix issue with the nightly build. Eventually play again the migration which has been included in migrateTo12()
+ realm.schema.get("SpaceChildSummaryEntity")
+ ?.takeIf { !it.hasField(SpaceChildSummaryEntityFields.SUGGESTED) }
+ ?.addField(SpaceChildSummaryEntityFields.SUGGESTED, Boolean::class.java)
+ ?.setNullable(SpaceChildSummaryEntityFields.SUGGESTED, true)
+ }
+
+ private fun migrateTo14(realm: DynamicRealm) {
+ Timber.d("Step 13 -> 14")
+ val roomAccountDataSchema = realm.schema.create("RoomAccountDataEntity")
+ .addField(RoomAccountDataEntityFields.CONTENT_STR, String::class.java)
+ .addField(RoomAccountDataEntityFields.TYPE, String::class.java, FieldAttribute.INDEXED)
+
+ realm.schema.get("RoomEntity")
+ ?.addRealmListField(RoomEntityFields.ACCOUNT_DATA.`$`, roomAccountDataSchema)
+
+ realm.schema.get("RoomSummaryEntity")
+ ?.addField(RoomSummaryEntityFields.IS_HIDDEN_FROM_USER, Boolean::class.java, FieldAttribute.INDEXED)
+ ?.transform {
+ val isHiddenFromUser = it.getString(RoomSummaryEntityFields.VERSIONING_STATE_STR) == VersioningState.UPGRADED_ROOM_JOINED.name
+ it.setBoolean(RoomSummaryEntityFields.IS_HIDDEN_FROM_USER, isHiddenFromUser)
+ }
+
+ roomAccountDataSchema.isEmbedded = true
+ }
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/AccountDataMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/AccountDataMapper.kt
index 54315a1835..dca0f927ad 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/AccountDataMapper.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/AccountDataMapper.kt
@@ -17,9 +17,11 @@
package org.matrix.android.sdk.internal.database.mapper
import com.squareup.moshi.Moshi
-import org.matrix.android.sdk.api.util.JSON_DICT_PARAMETERIZED_TYPE
-import org.matrix.android.sdk.internal.database.model.UserAccountDataEntity
import org.matrix.android.sdk.api.session.accountdata.UserAccountDataEvent
+import org.matrix.android.sdk.api.session.room.accountdata.RoomAccountDataEvent
+import org.matrix.android.sdk.api.util.JSON_DICT_PARAMETERIZED_TYPE
+import org.matrix.android.sdk.internal.database.model.RoomAccountDataEntity
+import org.matrix.android.sdk.internal.database.model.UserAccountDataEntity
import javax.inject.Inject
internal class AccountDataMapper @Inject constructor(moshi: Moshi) {
@@ -32,4 +34,12 @@ internal class AccountDataMapper @Inject constructor(moshi: Moshi) {
content = entity.contentStr?.let { adapter.fromJson(it) }.orEmpty()
)
}
+
+ fun map(roomId: String, entity: RoomAccountDataEntity): RoomAccountDataEvent {
+ return RoomAccountDataEvent(
+ roomId = roomId,
+ type = entity.type ?: "",
+ content = entity.contentStr?.let { adapter.fromJson(it) }.orEmpty()
+ )
+ }
}
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 a4a2fadd21..613b38e340 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
@@ -80,6 +80,7 @@ internal object EventMapper {
).also {
it.ageLocalTs = eventEntity.ageLocalTs
it.sendState = eventEntity.sendState
+ it.sendStateDetails = eventEntity.sendStateDetails
eventEntity.decryptionResultJson?.let { json ->
try {
it.mxDecryptionResult = MoshiProvider.providesMoshi().adapter(OlmDecryptionResult::class.java).fromJson(json)
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 6dc70b60fc..c32c019625 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
@@ -16,7 +16,10 @@
package org.matrix.android.sdk.internal.database.mapper
+import org.matrix.android.sdk.api.session.room.model.RoomJoinRules
import org.matrix.android.sdk.api.session.room.model.RoomSummary
+import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo
+import org.matrix.android.sdk.api.session.room.model.SpaceParentInfo
import org.matrix.android.sdk.api.session.room.model.tag.RoomTag
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity
import org.matrix.android.sdk.internal.session.typing.DefaultTypingUsersTracker
@@ -42,7 +45,9 @@ internal class RoomSummaryMapper @Inject constructor(private val timelineEventMa
name = roomSummaryEntity.name ?: "",
topic = roomSummaryEntity.topic ?: "",
avatarUrl = roomSummaryEntity.avatarUrl ?: "",
+ joinRules = roomSummaryEntity.joinRules,
isDirect = roomSummaryEntity.isDirect,
+ directUserId = roomSummaryEntity.directUserId,
latestPreviewableEvent = latestEvent,
joinedMembersCount = roomSummaryEntity.joinedMembersCount,
invitedMembersCount = roomSummaryEntity.invitedMembersCount,
@@ -63,7 +68,36 @@ internal class RoomSummaryMapper @Inject constructor(private val timelineEventMa
breadcrumbsIndex = roomSummaryEntity.breadcrumbsIndex,
roomEncryptionTrustLevel = roomSummaryEntity.roomEncryptionTrustLevel,
inviterId = roomSummaryEntity.inviterId,
- hasFailedSending = roomSummaryEntity.hasFailedSending
+ hasFailedSending = roomSummaryEntity.hasFailedSending,
+ roomType = roomSummaryEntity.roomType,
+ spaceParents = roomSummaryEntity.parents.map { relationInfoEntity ->
+ SpaceParentInfo(
+ parentId = relationInfoEntity.parentRoomId,
+ roomSummary = relationInfoEntity.parentSummaryEntity?.let { map(it) },
+ canonical = relationInfoEntity.canonical ?: false,
+ viaServers = relationInfoEntity.viaServers.toList()
+ )
+ },
+ spaceChildren = roomSummaryEntity.children.map {
+ SpaceChildInfo(
+ childRoomId = it.childRoomId ?: "",
+ isKnown = it.childSummaryEntity != null,
+ roomType = it.childSummaryEntity?.roomType,
+ name = it.childSummaryEntity?.name,
+ topic = it.childSummaryEntity?.topic,
+ avatarUrl = it.childSummaryEntity?.avatarUrl,
+ activeMemberCount = it.childSummaryEntity?.joinedMembersCount,
+ order = it.order,
+ autoJoin = it.autoJoin ?: false,
+ viaServers = it.viaServers.toList(),
+ parentRoomId = roomSummaryEntity.roomId,
+ suggested = it.suggested,
+ canonicalAlias = it.childSummaryEntity?.canonicalAlias,
+ aliases = it.childSummaryEntity?.aliases?.toList(),
+ worldReadable = it.childSummaryEntity?.joinRules == RoomJoinRules.PUBLIC
+ )
+ },
+ flattenParentIds = roomSummaryEntity.flattenParentIds?.split("|") ?: emptyList()
)
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/EventEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/EventEntity.kt
index fe59f4fceb..c9edbcd889 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/EventEntity.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/EventEntity.kt
@@ -32,6 +32,8 @@ internal open class EventEntity(@Index var eventId: String = "",
@Index var stateKey: String? = null,
var originServerTs: Long? = null,
@Index var sender: String? = null,
+ // Can contain a serialized MatrixError
+ var sendStateDetails: String? = null,
var age: Long? = 0,
var unsignedData: String? = null,
var redacts: String? = null,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/RoomAccountDataEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/RoomAccountDataEntity.kt
new file mode 100644
index 0000000000..40040b5738
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/RoomAccountDataEntity.kt
@@ -0,0 +1,27 @@
+/*
+ * 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.Index
+import io.realm.annotations.RealmClass
+
+@RealmClass(embedded = true)
+internal open class RoomAccountDataEntity(
+ @Index var type: String? = null,
+ var contentStr: String? = null
+) : RealmObject()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/RoomEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/RoomEntity.kt
index 3ff2532604..65483e05bf 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/RoomEntity.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/RoomEntity.kt
@@ -23,7 +23,8 @@ import io.realm.annotations.PrimaryKey
internal open class RoomEntity(@PrimaryKey var roomId: String = "",
var chunks: RealmList = RealmList(),
- var sendingTimelineEvents: RealmList = RealmList()
+ var sendingTimelineEvents: RealmList = RealmList(),
+ var accountData: RealmList = RealmList()
) : RealmObject() {
private var membershipStr: String = Membership.NONE.name
@@ -43,6 +44,5 @@ internal open class RoomEntity(@PrimaryKey var roomId: String = "",
set(value) {
membersLoadStatusStr = value.name
}
-
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 c87ac15a78..64dc08e827 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
@@ -21,13 +21,18 @@ import io.realm.RealmObject
import io.realm.annotations.Index
import io.realm.annotations.PrimaryKey
import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel
+import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.session.room.model.Membership
+import org.matrix.android.sdk.api.session.room.model.RoomJoinRules
import org.matrix.android.sdk.api.session.room.model.RoomSummary
import org.matrix.android.sdk.api.session.room.model.VersioningState
import org.matrix.android.sdk.api.session.room.model.tag.RoomTag
internal open class RoomSummaryEntity(
- @PrimaryKey var roomId: String = ""
+ @PrimaryKey var roomId: String = "",
+ var roomType: String? = null,
+ var parents: RealmList = RealmList(),
+ var children: RealmList = RealmList()
) : RealmObject() {
var displayName: String? = ""
@@ -204,6 +209,16 @@ internal open class RoomSummaryEntity(
if (value != field) field = value
}
+ var flattenParentIds: String? = null
+ set(value) {
+ if (value != field) field = value
+ }
+
+ var groupIds: String? = null
+ set(value) {
+ if (value != field) field = value
+ }
+
@Index
private var membershipStr: String = Membership.NONE.name
@@ -217,6 +232,12 @@ internal open class RoomSummaryEntity(
}
}
+ @Index
+ var isHiddenFromUser: Boolean = false
+ set(value) {
+ if (value != field) field = value
+ }
+
@Index
private var versioningStateStr: String = VersioningState.NONE.name
var versioningState: VersioningState
@@ -229,6 +250,19 @@ internal open class RoomSummaryEntity(
}
}
+ private var joinRulesStr: String? = null
+ var joinRules: RoomJoinRules?
+ get() {
+ return joinRulesStr?.let {
+ tryOrNull { RoomJoinRules.valueOf(it) }
+ }
+ }
+ set(value) {
+ if (value?.name != joinRulesStr) {
+ joinRulesStr = value?.name
+ }
+ }
+
var roomEncryptionTrustLevel: RoomEncryptionTrustLevel?
get() {
return roomEncryptionTrustLevelStr?.let {
@@ -244,6 +278,5 @@ internal open class RoomSummaryEntity(
roomEncryptionTrustLevelStr = value?.name
}
}
-
companion object
}
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 6e6096cf8a..19472e21d9 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
@@ -61,6 +61,9 @@ import io.realm.annotations.RealmModule
CurrentStateEventEntity::class,
UserAccountDataEntity::class,
ScalarTokenEntity::class,
- WellknownIntegrationManagerConfigEntity::class
+ WellknownIntegrationManagerConfigEntity::class,
+ RoomAccountDataEntity::class,
+ SpaceChildSummaryEntity::class,
+ SpaceParentSummaryEntity::class
])
internal class SessionRealmModule
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/SpaceChildSummaryEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/SpaceChildSummaryEntity.kt
new file mode 100644
index 0000000000..ce1afbb507
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/SpaceChildSummaryEntity.kt
@@ -0,0 +1,46 @@
+/*
+ * 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
+
+/**
+ * Decorates room summary with space related information.
+ */
+internal open class SpaceChildSummaryEntity(
+// var isSpace: Boolean = false,
+
+ var order: String? = null,
+
+ var autoJoin: Boolean? = null,
+
+ var suggested: Boolean? = null,
+
+ var childRoomId: String? = null,
+ // Link to the actual space summary if it is known locally
+ var childSummaryEntity: RoomSummaryEntity? = null,
+
+ var viaServers: RealmList = RealmList()
+// var owner: RoomSummaryEntity? = null,
+
+// var level: Int = 0
+
+) : RealmObject() {
+
+ companion object
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/SpaceParentSummaryEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/SpaceParentSummaryEntity.kt
new file mode 100644
index 0000000000..30517717f4
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/SpaceParentSummaryEntity.kt
@@ -0,0 +1,45 @@
+/*
+ * 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
+
+/**
+ * Decorates room summary with space related information.
+ */
+internal open class SpaceParentSummaryEntity(
+ /**
+ * Determines whether this is the main parent for the space
+ * When a user joins a room with a canonical parent, clients may switch to view the room in the context of that space,
+ * peeking into it in order to find other rooms and group them together.
+ * In practice, well behaved rooms should only have one canonical parent, but given this is not enforced:
+ * if multiple are present the client should select the one with the lowest room ID,
+ * as determined via a lexicographic utf-8 ordering.
+ */
+ var canonical: Boolean? = null,
+
+ var parentRoomId: String? = null,
+ // Link to the actual space summary if it is known locally
+ var parentSummaryEntity: RoomSummaryEntity? = null,
+
+ var viaServers: RealmList = RealmList()
+
+) : RealmObject() {
+
+ companion object
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/RoomEntityQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/RoomEntityQueries.kt
index 27e8d9d8d1..a551f97379 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/RoomEntityQueries.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/RoomEntityQueries.kt
@@ -29,6 +29,10 @@ internal fun RoomEntity.Companion.where(realm: Realm, roomId: String): RealmQuer
.equalTo(RoomEntityFields.ROOM_ID, roomId)
}
+internal fun RoomEntity.Companion.getOrCreate(realm: Realm, roomId: String): RoomEntity {
+ return where(realm, roomId).findFirst() ?: realm.createObject(RoomEntity::class.java, roomId)
+}
+
internal fun RoomEntity.Companion.where(realm: Realm, membership: Membership? = null): RealmQuery {
val query = realm.where()
if (membership != null) {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MatrixComponent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MatrixComponent.kt
index 9d6fa29bb2..5bc519e960 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MatrixComponent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MatrixComponent.kt
@@ -36,6 +36,7 @@ import org.matrix.android.sdk.internal.session.TestInterceptor
import org.matrix.android.sdk.internal.task.TaskExecutor
import org.matrix.android.sdk.internal.util.BackgroundDetectionObserver
import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers
+import org.matrix.android.sdk.internal.util.system.SystemModule
import org.matrix.olm.OlmManager
import java.io.File
@@ -44,6 +45,7 @@ import java.io.File
NetworkModule::class,
AuthModule::class,
RawModule::class,
+ SystemModule::class,
NoOpTestModule::class
])
@MatrixScope
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/legacy/DefaultLegacySessionImporter.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/legacy/DefaultLegacySessionImporter.kt
index e0e2f96fa9..4586cfea1e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/legacy/DefaultLegacySessionImporter.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/legacy/DefaultLegacySessionImporter.kt
@@ -153,7 +153,7 @@ internal class DefaultLegacySessionImporter @Inject constructor(
}
private fun importCryptoDb(legacyConfig: LegacyHomeServerConnectionConfig) {
- // Here we migrate the DB, we copy the crypto DB to the location specific to RiotX, and we encrypt it.
+ // Here we migrate the DB, we copy the crypto DB to the location specific to Matrix SDK2, and we encrypt it.
val userMd5 = legacyConfig.credentials.userId.md5()
val sessionId = legacyConfig.credentials.let { (if (it.deviceId.isNullOrBlank()) it.userId else "${it.userId}|${it.deviceId}").md5() }
@@ -177,12 +177,12 @@ internal class DefaultLegacySessionImporter @Inject constructor(
Timber.d("Migration: copy DB to encrypted DB")
Realm.getInstance(realmConfiguration).use {
- // Move the DB to the new location, handled by RiotX
+ // Move the DB to the new location, handled by Matrix SDK2
it.writeEncryptedCopyTo(File(newLocation, realmConfiguration.realmFileName), realmKeysUtils.getRealmEncryptionKey(keyAlias))
}
}
- // Delete all the files created by Riot Android which will not be used anymore by RiotX
+ // Delete all the files created by Riot Android which will not be used anymore by Element
private fun clearFileSystem(legacyConfig: LegacyHomeServerConnectionConfig) {
val cryptoFolder = legacyConfig.credentials.userId.md5()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/GlobalErrorHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/GlobalErrorHandler.kt
index 9afdb40ed1..8be11e80f3 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/GlobalErrorHandler.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/GlobalErrorHandler.kt
@@ -16,13 +16,13 @@
package org.matrix.android.sdk.internal.network
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.failure.GlobalError
import org.matrix.android.sdk.internal.auth.SessionParamsStore
import org.matrix.android.sdk.internal.di.SessionId
import org.matrix.android.sdk.internal.session.SessionScope
import org.matrix.android.sdk.internal.task.TaskExecutor
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.launch
import timber.log.Timber
import javax.inject.Inject
@@ -44,7 +44,6 @@ internal class GlobalErrorHandler @Inject constructor(
sessionParamsStore.setTokenInvalid(sessionId)
}
}
-
listener?.onGlobalError(globalError)
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/Request.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/Request.kt
index 0246bae024..e045cebd3e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/Request.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/Request.kt
@@ -88,8 +88,8 @@ internal suspend inline fun executeRequest(globalErrorReceiver: GlobalErr
throw when (exception) {
is IOException -> Failure.NetworkConnection(exception)
is Failure.ServerError,
- is Failure.OtherServerError -> exception
- is CancellationException -> Failure.Cancelled(exception)
+ is Failure.OtherServerError,
+ is CancellationException -> exception
else -> Failure.Unknown(exception)
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/RetrofitExtensions.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/RetrofitExtensions.kt
index 7132b4ff7a..2116063626 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/RetrofitExtensions.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/RetrofitExtensions.kt
@@ -25,6 +25,7 @@ import org.matrix.android.sdk.api.failure.MatrixError
import org.matrix.android.sdk.internal.di.MoshiProvider
import kotlinx.coroutines.suspendCancellableCoroutine
import okhttp3.ResponseBody
+import org.matrix.android.sdk.api.extensions.orFalse
import retrofit2.HttpException
import retrofit2.Response
import timber.log.Timber
@@ -91,7 +92,7 @@ private fun toFailure(errorBody: ResponseBody?, httpCode: Int, globalErrorReceiv
} else if (httpCode == HttpURLConnection.HTTP_UNAUTHORIZED /* 401 */
&& matrixError.code == MatrixError.M_UNKNOWN_TOKEN) {
// Also send this error to the globalErrorReceiver, for a global management
- globalErrorReceiver?.handleGlobalError(GlobalError.InvalidToken(matrixError.isSoftLogout))
+ globalErrorReceiver?.handleGlobalError(GlobalError.InvalidToken(matrixError.isSoftLogout.orFalse()))
}
return Failure.ServerError(matrixError, httpCode)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/UserAgentHolder.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/UserAgentHolder.kt
index 973c120f59..1a88404128 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/UserAgentHolder.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/UserAgentHolder.kt
@@ -36,7 +36,7 @@ internal class UserAgentHolder @Inject constructor(private val context: Context,
/**
* Create an user agent with the application version.
- * Ex: RiotX/1.0.0 (Linux; U; Android 6.0.1; SM-A510F Build/MMB29; Flavour GPlay; MatrixAndroidSDK_X 1.0)
+ * Ex: Element/1.0.0 (Linux; U; Android 6.0.1; SM-A510F Build/MMB29; Flavour GPlay; MatrixAndroidSDK_X 1.0)
*
* @param flavorDescription the flavor description
*/
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/query/QueryRoomOrderProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/query/QueryRoomOrderProcessor.kt
new file mode 100644
index 0000000000..7a06c2129c
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/query/QueryRoomOrderProcessor.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2021 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.internal.query
+
+import io.realm.RealmQuery
+import io.realm.Sort
+import org.matrix.android.sdk.api.session.room.RoomSortOrder
+import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity
+import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields
+
+internal fun RealmQuery.process(sortOrder: RoomSortOrder): RealmQuery {
+ when (sortOrder) {
+ RoomSortOrder.NAME -> {
+ sort(RoomSummaryEntityFields.DISPLAY_NAME, Sort.ASCENDING)
+ }
+ RoomSortOrder.ACTIVITY -> {
+ sort(RoomSummaryEntityFields.LAST_ACTIVITY_TIME, Sort.DESCENDING)
+ }
+ RoomSortOrder.NONE -> {
+ }
+ }
+ return this
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/query/QueryStringValueProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/query/QueryStringValueProcessor.kt
index 899024458a..fd33682231 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/query/QueryStringValueProcessor.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/query/QueryStringValueProcessor.kt
@@ -16,10 +16,10 @@
package org.matrix.android.sdk.internal.query
-import org.matrix.android.sdk.api.query.QueryStringValue
import io.realm.Case
import io.realm.RealmObject
import io.realm.RealmQuery
+import org.matrix.android.sdk.api.query.QueryStringValue
import timber.log.Timber
fun RealmQuery.process(field: String, queryStringValue: QueryStringValue): RealmQuery {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultFileService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultFileService.kt
index d05ee48c1b..a284d976d0 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultFileService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultFileService.kt
@@ -219,7 +219,7 @@ internal class DefaultFileService @Inject constructor(
fileName: String,
mimeType: String?,
elementToDecrypt: ElementToDecrypt?): Boolean {
- return fileState(mxcUrl, fileName, mimeType, elementToDecrypt) == FileService.FileState.IN_CACHE
+ return fileState(mxcUrl, fileName, mimeType, elementToDecrypt) is FileService.FileState.InCache
}
internal data class CachedFiles(
@@ -256,12 +256,17 @@ internal class DefaultFileService @Inject constructor(
fileName: String,
mimeType: String?,
elementToDecrypt: ElementToDecrypt?): FileService.FileState {
- mxcUrl ?: return FileService.FileState.UNKNOWN
- if (getFiles(mxcUrl, fileName, mimeType, elementToDecrypt != null).file.exists()) return FileService.FileState.IN_CACHE
+ mxcUrl ?: return FileService.FileState.Unknown
+ val files = getFiles(mxcUrl, fileName, mimeType, elementToDecrypt != null)
+ if (files.file.exists()) {
+ return FileService.FileState.InCache(
+ decryptedFileInCache = files.getClearFile().exists()
+ )
+ }
val isDownloading = synchronized(ongoing) {
ongoing[mxcUrl] != null
}
- return if (isDownloading) FileService.FileState.DOWNLOADING else FileService.FileState.UNKNOWN
+ return if (isDownloading) FileService.FileState.Downloading else FileService.FileState.Unknown
}
/**
@@ -286,7 +291,7 @@ internal class DefaultFileService @Inject constructor(
Timber.v("Get size of ${it.absolutePath}")
true
}
- .sumBy { it.length().toInt() }
+ .sumOf { it.length().toInt() }
}
override fun clearCache() {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt
index 821a9cba8c..1cf99bbbd7 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt
@@ -19,15 +19,17 @@ package org.matrix.android.sdk.internal.session
import androidx.annotation.MainThread
import dagger.Lazy
import io.realm.RealmConfiguration
+import kotlinx.coroutines.NonCancellable
+import kotlinx.coroutines.withContext
import okhttp3.OkHttpClient
import org.matrix.android.sdk.api.auth.data.SessionParams
import org.matrix.android.sdk.api.failure.GlobalError
import org.matrix.android.sdk.api.federation.FederationService
import org.matrix.android.sdk.api.pushrules.PushRuleService
-import org.matrix.android.sdk.api.session.initsync.InitialSyncProgressService
import org.matrix.android.sdk.api.session.Session
+import org.matrix.android.sdk.api.session.SessionLifecycleObserver
import org.matrix.android.sdk.api.session.account.AccountService
-import org.matrix.android.sdk.api.session.accountdata.AccountDataService
+import org.matrix.android.sdk.api.session.accountdata.SessionAccountDataService
import org.matrix.android.sdk.api.session.cache.CacheService
import org.matrix.android.sdk.api.session.call.CallSignalingService
import org.matrix.android.sdk.api.session.content.ContentUploadStateTracker
@@ -38,8 +40,10 @@ 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.initsync.InitialSyncProgressService
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
import org.matrix.android.sdk.api.session.permalinks.PermalinkService
import org.matrix.android.sdk.api.session.profile.ProfileService
import org.matrix.android.sdk.api.session.pushers.PushersService
@@ -49,6 +53,7 @@ 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.sync.FilterService
import org.matrix.android.sdk.api.session.terms.TermsService
import org.matrix.android.sdk.api.session.thirdparty.ThirdPartyService
@@ -112,7 +117,7 @@ internal class DefaultSession @Inject constructor(
private val contentDownloadStateTracker: ContentDownloadStateTracker,
private val initialSyncProgressService: Lazy,
private val homeServerCapabilitiesService: Lazy,
- private val accountDataService: Lazy,
+ private val accountDataService: Lazy,
private val _sharedSecretStorageService: Lazy,
private val accountService: Lazy,
private val eventService: Lazy,
@@ -120,9 +125,12 @@ internal class DefaultSession @Inject constructor(
private val integrationManagerService: IntegrationManagerService,
private val thirdPartyService: Lazy,
private val callSignalingService: Lazy,
+ private val spaceService: Lazy,
+ private val openIdService: Lazy,
@UnauthenticatedWithCertificate
private val unauthenticatedWithCertificateOkHttpClient: Lazy
) : Session,
+ GlobalErrorHandler.Listener,
RoomService by roomService.get(),
RoomDirectoryService by roomDirectoryService.get(),
GroupService by groupService.get(),
@@ -137,9 +145,7 @@ internal class DefaultSession @Inject constructor(
SecureStorageService by secureStorageService.get(),
HomeServerCapabilitiesService by homeServerCapabilitiesService.get(),
ProfileService by profileService.get(),
- AccountDataService by accountDataService.get(),
- AccountService by accountService.get(),
- GlobalErrorHandler.Listener {
+ AccountService by accountService.get() {
override val sharedSecretStorageService: SharedSecretStorageService
get() = _sharedSecretStorageService.get()
@@ -157,11 +163,16 @@ internal class DefaultSession @Inject constructor(
override fun open() {
assert(!isOpen)
isOpen = true
+ globalErrorHandler.listener = this
cryptoService.get().ensureDevice()
uiHandler.post {
- lifecycleObservers.forEach { it.onSessionStarted() }
+ lifecycleObservers.forEach {
+ it.onSessionStarted(this)
+ }
+ sessionListeners.dispatch { _, listener ->
+ listener.onSessionStarted(this)
+ }
}
- globalErrorHandler.listener = this
}
override fun requireBackgroundSync() {
@@ -200,11 +211,14 @@ internal class DefaultSession @Inject constructor(
stopSync()
// timelineEventDecryptor.destroy()
uiHandler.post {
- lifecycleObservers.forEach { it.onSessionStopped() }
+ lifecycleObservers.forEach { it.onSessionStopped(this) }
+ sessionListeners.dispatch { _, listener ->
+ listener.onSessionStopped(this)
+ }
}
cryptoService.get().close()
- isOpen = false
globalErrorHandler.listener = null
+ isOpen = false
}
override fun getSyncStateLive() = getSyncThread().liveState()
@@ -225,14 +239,23 @@ internal class DefaultSession @Inject constructor(
stopSync()
stopAnyBackgroundSync()
uiHandler.post {
- lifecycleObservers.forEach { it.onClearCache() }
+ lifecycleObservers.forEach {
+ it.onClearCache(this)
+ }
+ sessionListeners.dispatch { _, listener ->
+ listener.onClearCache(this)
+ }
+ }
+ withContext(NonCancellable) {
+ cacheService.get().clearCache()
}
- cacheService.get().clearCache()
workManagerProvider.cancelAllWorks()
}
override fun onGlobalError(globalError: GlobalError) {
- sessionListeners.dispatchGlobalError(globalError)
+ sessionListeners.dispatch { _, listener ->
+ listener.onGlobalError(this, globalError)
+ }
}
override fun contentUrlResolver() = contentUrlResolver
@@ -265,6 +288,12 @@ internal class DefaultSession @Inject constructor(
override fun thirdPartyService(): ThirdPartyService = thirdPartyService.get()
+ override fun spaceService(): SpaceService = spaceService.get()
+
+ override fun openIdService(): OpenIdService = openIdService.get()
+
+ override fun accountDataService(): SessionAccountDataService = accountDataService.get()
+
override fun getOkHttpClient(): OkHttpClient {
return unauthenticatedWithCertificateOkHttpClient.get()
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionComponent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionComponent.kt
index 7e1e3d0f70..9a936b73c2 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionComponent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionComponent.kt
@@ -52,6 +52,7 @@ import org.matrix.android.sdk.internal.session.room.send.RedactEventWorker
import org.matrix.android.sdk.internal.session.room.send.SendEventWorker
import org.matrix.android.sdk.internal.session.search.SearchModule
import org.matrix.android.sdk.internal.session.signout.SignOutModule
+import org.matrix.android.sdk.internal.session.space.SpaceModule
import org.matrix.android.sdk.internal.session.sync.SyncModule
import org.matrix.android.sdk.internal.session.sync.SyncTask
import org.matrix.android.sdk.internal.session.sync.SyncTokenStore
@@ -63,6 +64,7 @@ import org.matrix.android.sdk.internal.session.user.accountdata.AccountDataModul
import org.matrix.android.sdk.internal.session.widgets.WidgetModule
import org.matrix.android.sdk.internal.task.TaskExecutor
import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers
+import org.matrix.android.sdk.internal.util.system.SystemModule
@Component(dependencies = [MatrixComponent::class],
modules = [
@@ -79,6 +81,7 @@ import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers
CacheModule::class,
MediaModule::class,
CryptoModule::class,
+ SystemModule::class,
PushersModule::class,
OpenIdModule::class,
WidgetModule::class,
@@ -91,7 +94,8 @@ import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers
FederationModule::class,
CallModule::class,
SearchModule::class,
- ThirdPartyModule::class
+ ThirdPartyModule::class,
+ SpaceModule::class
]
)
@SessionScope
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionCoroutineScopeHolder.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionCoroutineScopeHolder.kt
new file mode 100644
index 0000000000..82a8f79fd5
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionCoroutineScopeHolder.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2021 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.internal.session
+
+import kotlinx.coroutines.CancellationException
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.SupervisorJob
+import kotlinx.coroutines.cancelChildren
+import javax.inject.Inject
+import org.matrix.android.sdk.api.session.Session
+import org.matrix.android.sdk.api.session.SessionLifecycleObserver
+
+@SessionScope
+internal class SessionCoroutineScopeHolder @Inject constructor(): SessionLifecycleObserver {
+
+ val scope: CoroutineScope = CoroutineScope(SupervisorJob())
+
+ override fun onSessionStopped(session: Session) {
+ scope.cancelChildren()
+ }
+
+ override fun onClearCache(session: Session) {
+ scope.cancelChildren()
+ }
+
+ private fun CoroutineScope.cancelChildren() {
+ coroutineContext.cancelChildren(CancellationException("Closing session"))
+ }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionListeners.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionListeners.kt
index 64f2d249f3..d5c661b1e4 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionListeners.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionListeners.kt
@@ -16,11 +16,17 @@
package org.matrix.android.sdk.internal.session
-import org.matrix.android.sdk.api.failure.GlobalError
+import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.session.Session
+import org.matrix.android.sdk.internal.SessionManager
+import org.matrix.android.sdk.internal.di.SessionId
+import timber.log.Timber
import javax.inject.Inject
-internal class SessionListeners @Inject constructor() {
+@SessionScope
+internal class SessionListeners @Inject constructor(
+ @SessionId private val sessionId: String,
+ private val sessionManager: SessionManager) {
private val listeners = mutableSetOf()
@@ -36,11 +42,18 @@ internal class SessionListeners @Inject constructor() {
}
}
- fun dispatchGlobalError(globalError: GlobalError) {
+ fun dispatch(block: (Session, Session.Listener) -> Unit) {
synchronized(listeners) {
+ val session = getSession() ?: return Unit.also {
+ Timber.w("You don't have any attached session")
+ }
listeners.forEach {
- it.onGlobalError(globalError)
+ tryOrNull { block(session, it) }
}
}
}
+
+ private fun getSession(): Session? {
+ return sessionManager.getSessionComponent(sessionId)?.session()
+ }
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt
index e61e4ecd89..e6da21315b 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt
@@ -33,10 +33,12 @@ import org.matrix.android.sdk.api.auth.data.SessionParams
import org.matrix.android.sdk.api.auth.data.sessionId
import org.matrix.android.sdk.api.crypto.MXCryptoConfig
import org.matrix.android.sdk.api.session.Session
-import org.matrix.android.sdk.api.session.accountdata.AccountDataService
+import org.matrix.android.sdk.api.session.SessionLifecycleObserver
+import org.matrix.android.sdk.api.session.accountdata.SessionAccountDataService
import org.matrix.android.sdk.api.session.events.EventService
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilitiesService
import org.matrix.android.sdk.api.session.initsync.InitialSyncProgressService
+import org.matrix.android.sdk.api.session.openid.OpenIdService
import org.matrix.android.sdk.api.session.permalinks.PermalinkService
import org.matrix.android.sdk.api.session.securestorage.SecureStorageService
import org.matrix.android.sdk.api.session.securestorage.SharedSecretStorageService
@@ -81,6 +83,7 @@ import org.matrix.android.sdk.internal.session.homeserver.DefaultHomeServerCapab
import org.matrix.android.sdk.internal.session.identity.DefaultIdentityService
import org.matrix.android.sdk.internal.session.initsync.DefaultInitialSyncProgressService
import org.matrix.android.sdk.internal.session.integrationmanager.IntegrationManager
+import org.matrix.android.sdk.internal.session.openid.DefaultOpenIdService
import org.matrix.android.sdk.internal.session.permalinks.DefaultPermalinkService
import org.matrix.android.sdk.internal.session.room.EventRelationsAggregationProcessor
import org.matrix.android.sdk.internal.session.room.create.RoomCreateEventProcessor
@@ -90,7 +93,7 @@ import org.matrix.android.sdk.internal.session.room.send.queue.EventSenderProces
import org.matrix.android.sdk.internal.session.room.tombstone.RoomTombstoneEventProcessor
import org.matrix.android.sdk.internal.session.securestorage.DefaultSecureStorageService
import org.matrix.android.sdk.internal.session.typing.DefaultTypingUsersTracker
-import org.matrix.android.sdk.internal.session.user.accountdata.DefaultAccountDataService
+import org.matrix.android.sdk.internal.session.user.accountdata.DefaultSessionAccountDataService
import org.matrix.android.sdk.internal.session.widgets.DefaultWidgetURLFormatter
import org.matrix.android.sdk.internal.util.md5
import retrofit2.Retrofit
@@ -343,6 +346,10 @@ internal abstract class SessionModule {
@IntoSet
abstract fun bindRealmSessionProvider(provider: RealmSessionProvider): SessionLifecycleObserver
+ @Binds
+ @IntoSet
+ abstract fun bindSessionCoroutineScopeHolder(holder: SessionCoroutineScopeHolder): SessionLifecycleObserver
+
@Binds
@IntoSet
abstract fun bindEventSenderProcessorAsSessionLifecycleObserver(processor: EventSenderProcessorCoroutine): SessionLifecycleObserver
@@ -357,7 +364,7 @@ internal abstract class SessionModule {
abstract fun bindHomeServerCapabilitiesService(service: DefaultHomeServerCapabilitiesService): HomeServerCapabilitiesService
@Binds
- abstract fun bindAccountDataService(service: DefaultAccountDataService): AccountDataService
+ abstract fun bindSessionAccountDataService(service: DefaultSessionAccountDataService): SessionAccountDataService
@Binds
abstract fun bindEventService(service: DefaultEventService): EventService
@@ -368,6 +375,9 @@ internal abstract class SessionModule {
@Binds
abstract fun bindPermalinkService(service: DefaultPermalinkService): PermalinkService
+ @Binds
+ abstract fun bindOpenIdTokenService(service: DefaultOpenIdService): OpenIdService
+
@Binds
abstract fun bindTypingUsersTracker(tracker: DefaultTypingUsersTracker): TypingUsersTracker
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallEventProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallEventProcessor.kt
index a190ff62ac..8bf2014639 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallEventProcessor.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallEventProcessor.kt
@@ -37,7 +37,9 @@ internal class CallEventProcessor @Inject constructor(private val callSignalingH
EventType.CALL_CANDIDATES,
EventType.CALL_INVITE,
EventType.CALL_HANGUP,
- EventType.ENCRYPTED
+ EventType.ENCRYPTED,
+ EventType.CALL_ASSERTED_IDENTITY,
+ EventType.CALL_ASSERTED_IDENTITY_PREFIX
)
private val eventsToPostProcess = mutableListOf()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallListenersDispatcher.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallListenersDispatcher.kt
index 1de2d8a106..dad17f4ac9 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallListenersDispatcher.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallListenersDispatcher.kt
@@ -20,6 +20,7 @@ import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.session.call.CallListener
import org.matrix.android.sdk.api.session.call.MxCall
import org.matrix.android.sdk.api.session.room.model.call.CallAnswerContent
+import org.matrix.android.sdk.api.session.room.model.call.CallAssertedIdentityContent
import org.matrix.android.sdk.api.session.room.model.call.CallCandidatesContent
import org.matrix.android.sdk.api.session.room.model.call.CallHangupContent
import org.matrix.android.sdk.api.session.room.model.call.CallInviteContent
@@ -64,6 +65,10 @@ internal class CallListenersDispatcher(private val listeners: Set)
it.onCallNegotiateReceived(callNegotiateContent)
}
+ override fun onCallAssertedIdentityReceived(callAssertedIdentityContent: CallAssertedIdentityContent) = dispatch {
+ it.onCallAssertedIdentityReceived(callAssertedIdentityContent)
+ }
+
private fun dispatch(lambda: (CallListener) -> Unit) {
listeners.toList().forEach {
tryOrNull {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallSignalingHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallSignalingHandler.kt
index 8d7e9e819a..d18737d31b 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallSignalingHandler.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallSignalingHandler.kt
@@ -23,19 +23,17 @@ import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.room.model.call.CallAnswerContent
+import org.matrix.android.sdk.api.session.room.model.call.CallAssertedIdentityContent
import org.matrix.android.sdk.api.session.room.model.call.CallCandidatesContent
-import org.matrix.android.sdk.api.session.room.model.call.CallCapabilities
import org.matrix.android.sdk.api.session.room.model.call.CallHangupContent
import org.matrix.android.sdk.api.session.room.model.call.CallInviteContent
import org.matrix.android.sdk.api.session.room.model.call.CallNegotiateContent
import org.matrix.android.sdk.api.session.room.model.call.CallRejectContent
import org.matrix.android.sdk.api.session.room.model.call.CallSelectAnswerContent
-import org.matrix.android.sdk.api.session.room.model.call.CallSignallingContent
-import org.matrix.android.sdk.api.util.Optional
+import org.matrix.android.sdk.api.session.room.model.call.CallSignalingContent
import org.matrix.android.sdk.internal.di.UserId
import org.matrix.android.sdk.internal.session.SessionScope
import timber.log.Timber
-import java.math.BigDecimal
import javax.inject.Inject
@SessionScope
@@ -56,30 +54,44 @@ internal class CallSignalingHandler @Inject constructor(private val activeCallHa
fun onCallEvent(event: Event) {
when (event.getClearType()) {
- EventType.CALL_ANSWER -> {
+ EventType.CALL_ANSWER -> {
handleCallAnswerEvent(event)
}
- EventType.CALL_INVITE -> {
+ EventType.CALL_INVITE -> {
handleCallInviteEvent(event)
}
- EventType.CALL_HANGUP -> {
+ EventType.CALL_HANGUP -> {
handleCallHangupEvent(event)
}
- EventType.CALL_REJECT -> {
+ EventType.CALL_REJECT -> {
handleCallRejectEvent(event)
}
- EventType.CALL_CANDIDATES -> {
+ EventType.CALL_CANDIDATES -> {
handleCallCandidatesEvent(event)
}
- EventType.CALL_SELECT_ANSWER -> {
+ EventType.CALL_SELECT_ANSWER -> {
handleCallSelectAnswerEvent(event)
}
- EventType.CALL_NEGOTIATE -> {
+ EventType.CALL_NEGOTIATE -> {
handleCallNegotiateEvent(event)
}
+ EventType.CALL_ASSERTED_IDENTITY,
+ EventType.CALL_ASSERTED_IDENTITY_PREFIX -> {
+ handleCallAssertedIdentityEvent(event)
+ }
}
}
+ private fun handleCallAssertedIdentityEvent(event: Event) {
+ val content = event.getClearContent().toModel() ?: return
+ val call = content.getCall() ?: return
+ if (call.ourPartyId == content.partyId) {
+ // Ignore remote echo (not that we send asserted identity, but still...)
+ return
+ }
+ callListenersDispatcher.onCallAssertedIdentityReceived(content)
+ }
+
private fun handleCallNegotiateEvent(event: Event) {
val content = event.getClearContent().toModel() ?: return
val call = content.getCall() ?: return
@@ -192,6 +204,9 @@ internal class CallSignalingHandler @Inject constructor(private val activeCallHa
// Ignore remote echo
return
}
+ if (event.roomId == null || event.senderId == null) {
+ return
+ }
if (event.senderId == userId) {
// discard current call, it's answered by another of my session
activeCallHandler.removeCall(call.callId)
@@ -201,20 +216,16 @@ internal class CallSignalingHandler @Inject constructor(private val activeCallHa
Timber.v("Ignoring answer from party ID ${content.partyId} we already have an answer from ${call.opponentPartyId}")
return
}
- call.apply {
- opponentPartyId = Optional.from(content.partyId)
- opponentVersion = content.version?.let { BigDecimal(it).intValueExact() } ?: MxCall.VOIP_PROTO_VERSION
- capabilities = content.capabilities ?: CallCapabilities()
- }
+ mxCallFactory.updateOutgoingCallWithOpponentData(call, event.senderId, content, content.capabilities)
callListenersDispatcher.onCallAnswerReceived(content)
}
}
- private fun MxCall.partyIdsMatches(contentSignallingContent: CallSignallingContent): Boolean {
- return opponentPartyId?.getOrNull() == contentSignallingContent.partyId
+ private fun MxCall.partyIdsMatches(contentSignalingContent: CallSignalingContent): Boolean {
+ return opponentPartyId?.getOrNull() == contentSignalingContent.partyId
}
- private fun CallSignallingContent.getCall(): MxCall? {
+ private fun CallSignalingContent.getCall(): MxCall? {
val currentCall = callId?.let {
activeCallHandler.getCallWithId(it)
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/DefaultCallSignalingService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/DefaultCallSignalingService.kt
index 7d046cb642..da1f84cc89 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/DefaultCallSignalingService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/DefaultCallSignalingService.kt
@@ -19,7 +19,6 @@ package org.matrix.android.sdk.internal.session.call
import org.matrix.android.sdk.api.session.call.CallListener
import org.matrix.android.sdk.api.session.call.CallSignalingService
import org.matrix.android.sdk.api.session.call.MxCall
-import org.matrix.android.sdk.api.session.call.PSTNProtocolChecker
import org.matrix.android.sdk.api.session.call.TurnServerResponse
import org.matrix.android.sdk.internal.session.SessionScope
import timber.log.Timber
@@ -30,18 +29,13 @@ internal class DefaultCallSignalingService @Inject constructor(
private val callSignalingHandler: CallSignalingHandler,
private val mxCallFactory: MxCallFactory,
private val activeCallHandler: ActiveCallHandler,
- private val turnServerDataSource: TurnServerDataSource,
- private val pstnProtocolChecker: PSTNProtocolChecker
+ private val turnServerDataSource: TurnServerDataSource
) : CallSignalingService {
override suspend fun getTurnServer(): TurnServerResponse {
return turnServerDataSource.getTurnServer()
}
- override fun getPSTNProtocolChecker(): PSTNProtocolChecker {
- return pstnProtocolChecker
- }
-
override fun createOutgoingCall(roomId: String, otherUserId: String, isVideoCall: Boolean): MxCall {
return mxCallFactory.createOutgoingCall(roomId, otherUserId, isVideoCall).also {
activeCallHandler.addCall(it)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/MxCallFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/MxCallFactory.kt
index b14cdca63c..547be2253f 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/MxCallFactory.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/MxCallFactory.kt
@@ -17,18 +17,17 @@
package org.matrix.android.sdk.internal.session.call
import org.matrix.android.sdk.api.MatrixConfiguration
+import org.matrix.android.sdk.api.session.call.CallIdGenerator
import org.matrix.android.sdk.api.session.call.MxCall
import org.matrix.android.sdk.api.session.room.model.call.CallCapabilities
import org.matrix.android.sdk.api.session.room.model.call.CallInviteContent
-import org.matrix.android.sdk.api.util.Optional
+import org.matrix.android.sdk.api.session.room.model.call.CallSignalingContent
import org.matrix.android.sdk.internal.di.DeviceId
import org.matrix.android.sdk.internal.di.UserId
import org.matrix.android.sdk.internal.session.call.model.MxCallImpl
import org.matrix.android.sdk.internal.session.profile.GetProfileInfoTask
import org.matrix.android.sdk.internal.session.room.send.LocalEchoEventFactory
import org.matrix.android.sdk.internal.session.room.send.queue.EventSenderProcessor
-import java.math.BigDecimal
-import java.util.UUID
import javax.inject.Inject
internal class MxCallFactory @Inject constructor(
@@ -48,32 +47,38 @@ internal class MxCallFactory @Inject constructor(
roomId = roomId,
userId = userId,
ourPartyId = deviceId ?: "",
- opponentUserId = opponentUserId,
isVideoCall = content.isVideo(),
localEchoEventFactory = localEchoEventFactory,
eventSenderProcessor = eventSenderProcessor,
matrixConfiguration = matrixConfiguration,
getProfileInfoTask = getProfileInfoTask
).apply {
- opponentPartyId = Optional.from(content.partyId)
- opponentVersion = content.version?.let { BigDecimal(it).intValueExact() } ?: MxCall.VOIP_PROTO_VERSION
- capabilities = content.capabilities ?: CallCapabilities()
+ updateOpponentData(opponentUserId, content, content.capabilities)
}
}
fun createOutgoingCall(roomId: String, opponentUserId: String, isVideoCall: Boolean): MxCall {
return MxCallImpl(
- callId = UUID.randomUUID().toString(),
+ callId = CallIdGenerator.generate(),
isOutgoing = true,
roomId = roomId,
userId = userId,
ourPartyId = deviceId ?: "",
- opponentUserId = opponentUserId,
isVideoCall = isVideoCall,
localEchoEventFactory = localEchoEventFactory,
eventSenderProcessor = eventSenderProcessor,
matrixConfiguration = matrixConfiguration,
getProfileInfoTask = getProfileInfoTask
- )
+ ).apply {
+ // Setup with this userId, might be updated when processing the Answer event
+ this.opponentUserId = opponentUserId
+ }
+ }
+
+ fun updateOutgoingCallWithOpponentData(call: MxCall,
+ userId: String,
+ content: CallSignalingContent,
+ callCapabilities: CallCapabilities?) {
+ (call as? MxCallImpl)?.updateOpponentData(userId, content, callCapabilities)
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/model/MxCallImpl.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/model/MxCallImpl.kt
index 88fba0ea85..f101685a4b 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/model/MxCallImpl.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/model/MxCallImpl.kt
@@ -17,6 +17,7 @@
package org.matrix.android.sdk.internal.session.call.model
import org.matrix.android.sdk.api.MatrixConfiguration
+import org.matrix.android.sdk.api.session.call.CallIdGenerator
import org.matrix.android.sdk.api.session.call.CallState
import org.matrix.android.sdk.api.session.call.MxCall
import org.matrix.android.sdk.api.session.events.model.Content
@@ -36,6 +37,7 @@ import org.matrix.android.sdk.api.session.room.model.call.CallNegotiateContent
import org.matrix.android.sdk.api.session.room.model.call.CallRejectContent
import org.matrix.android.sdk.api.session.room.model.call.CallReplacesContent
import org.matrix.android.sdk.api.session.room.model.call.CallSelectAnswerContent
+import org.matrix.android.sdk.api.session.room.model.call.CallSignalingContent
import org.matrix.android.sdk.api.session.room.model.call.SdpType
import org.matrix.android.sdk.api.util.Optional
import org.matrix.android.sdk.internal.session.call.DefaultCallSignalingService
@@ -43,14 +45,13 @@ import org.matrix.android.sdk.internal.session.profile.GetProfileInfoTask
import org.matrix.android.sdk.internal.session.room.send.LocalEchoEventFactory
import org.matrix.android.sdk.internal.session.room.send.queue.EventSenderProcessor
import timber.log.Timber
-import java.util.UUID
+import java.math.BigDecimal
internal class MxCallImpl(
override val callId: String,
override val isOutgoing: Boolean,
override val roomId: String,
private val userId: String,
- override val opponentUserId: String,
override val isVideoCall: Boolean,
override val ourPartyId: String,
private val localEchoEventFactory: LocalEchoEventFactory,
@@ -61,8 +62,16 @@ internal class MxCallImpl(
override var opponentPartyId: Optional? = null
override var opponentVersion: Int = MxCall.VOIP_PROTO_VERSION
+ override lateinit var opponentUserId: String
override var capabilities: CallCapabilities? = null
+ fun updateOpponentData(userId: String, content: CallSignalingContent, callCapabilities: CallCapabilities?) {
+ opponentPartyId = Optional.from(content.partyId)
+ opponentVersion = content.version?.let { BigDecimal(it).intValueExact() } ?: MxCall.VOIP_PROTO_VERSION
+ opponentUserId = userId
+ capabilities = callCapabilities ?: CallCapabilities()
+ }
+
override var state: CallState = CallState.Idle
set(value) {
field = value
@@ -202,7 +211,10 @@ internal class MxCallImpl(
.also { eventSenderProcessor.postEvent(it) }
}
- override suspend fun transfer(targetUserId: String, targetRoomId: String?) {
+ override suspend fun transfer(targetUserId: String,
+ targetRoomId: String?,
+ createCallId: String?,
+ awaitCallId: String?) {
val profileInfoParams = GetProfileInfoTask.Params(targetUserId)
val profileInfo = try {
getProfileInfoTask.execute(profileInfoParams)
@@ -213,15 +225,16 @@ internal class MxCallImpl(
CallReplacesContent(
callId = callId,
partyId = ourPartyId,
- replacementId = UUID.randomUUID().toString(),
+ replacementId = CallIdGenerator.generate(),
version = MxCall.VOIP_PROTO_VERSION.toString(),
targetUser = CallReplacesContent.TargetUser(
id = targetUserId,
displayName = profileInfo?.get(ProfileService.DISPLAY_NAME_KEY) as? String,
avatarUrl = profileInfo?.get(ProfileService.AVATAR_URL_KEY) as? String
),
- targerRoomId = targetRoomId,
- createCall = UUID.randomUUID().toString()
+ targetRoomId = targetRoomId,
+ awaitCall = awaitCallId,
+ createCall = createCallId
)
.let { createEventAndLocalEcho(type = EventType.CALL_REPLACES, roomId = roomId, content = it.toContent()) }
.also { eventSenderProcessor.postEvent(it) }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/DefaultContentUploadStateTracker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/DefaultContentUploadStateTracker.kt
index 754f12bd68..17e0a930c1 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/DefaultContentUploadStateTracker.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/DefaultContentUploadStateTracker.kt
@@ -78,6 +78,16 @@ internal class DefaultContentUploadStateTracker @Inject constructor() : ContentU
updateState(key, progressData)
}
+ internal fun setCompressingImage(key: String) {
+ val progressData = ContentUploadStateTracker.State.CompressingImage
+ updateState(key, progressData)
+ }
+
+ internal fun setCompressingVideo(key: String, percent: Float) {
+ val progressData = ContentUploadStateTracker.State.CompressingVideo(percent)
+ updateState(key, progressData)
+ }
+
internal fun setProgress(key: String, current: Long, total: Long) {
val progressData = ContentUploadStateTracker.State.Uploading(current, total)
updateState(key, progressData)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/FileUploader.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/FileUploader.kt
index 8fa595db30..6a4dd26392 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/FileUploader.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/FileUploader.kt
@@ -31,24 +31,31 @@ import okhttp3.RequestBody.Companion.toRequestBody
import okio.BufferedSink
import okio.source
import org.matrix.android.sdk.api.extensions.tryOrNull
+import org.matrix.android.sdk.api.failure.Failure
+import org.matrix.android.sdk.api.failure.MatrixError
import org.matrix.android.sdk.api.session.content.ContentUrlResolver
+import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities
import org.matrix.android.sdk.internal.di.Authenticated
import org.matrix.android.sdk.internal.network.GlobalErrorReceiver
import org.matrix.android.sdk.internal.network.ProgressRequestBody
import org.matrix.android.sdk.internal.network.awaitResponse
import org.matrix.android.sdk.internal.network.toFailure
+import org.matrix.android.sdk.internal.session.homeserver.DefaultHomeServerCapabilitiesService
+import org.matrix.android.sdk.internal.util.TemporaryFileCreator
import java.io.File
import java.io.FileNotFoundException
import java.io.IOException
-import java.util.UUID
import javax.inject.Inject
-internal class FileUploader @Inject constructor(@Authenticated
- private val okHttpClient: OkHttpClient,
- private val globalErrorReceiver: GlobalErrorReceiver,
- private val context: Context,
- contentUrlResolver: ContentUrlResolver,
- moshi: Moshi) {
+internal class FileUploader @Inject constructor(
+ @Authenticated private val okHttpClient: OkHttpClient,
+ private val globalErrorReceiver: GlobalErrorReceiver,
+ private val homeServerCapabilitiesService: DefaultHomeServerCapabilitiesService,
+ private val context: Context,
+ private val temporaryFileCreator: TemporaryFileCreator,
+ contentUrlResolver: ContentUrlResolver,
+ moshi: Moshi
+) {
private val uploadUrl = contentUrlResolver.uploadUrl
private val responseAdapter = moshi.adapter(ContentUploadResponse::class.java)
@@ -57,6 +64,21 @@ internal class FileUploader @Inject constructor(@Authenticated
filename: String?,
mimeType: String?,
progressListener: ProgressRequestBody.Listener? = null): ContentUploadResponse {
+ // Check size limit
+ val maxUploadFileSize = homeServerCapabilitiesService.getHomeServerCapabilities().maxUploadFileSize
+
+ if (maxUploadFileSize != HomeServerCapabilities.MAX_UPLOAD_FILE_SIZE_UNKNOWN
+ && file.length() > maxUploadFileSize) {
+ // Known limitation and file too big for the server, save the pain to upload it
+ throw Failure.ServerError(
+ error = MatrixError(
+ code = MatrixError.M_TOO_LARGE,
+ message = "Cannot upload files larger than ${maxUploadFileSize / 1048576L}mb"
+ ),
+ httpCode = 413
+ )
+ }
+
val uploadBody = object : RequestBody() {
override fun contentLength() = file.length()
@@ -90,7 +112,7 @@ internal class FileUploader @Inject constructor(@Authenticated
val inputStream = withContext(Dispatchers.IO) {
context.contentResolver.openInputStream(uri)
} ?: throw FileNotFoundException()
- val workingFile = File.createTempFile(UUID.randomUUID().toString(), null, context.cacheDir)
+ val workingFile = temporaryFileCreator.create()
workingFile.outputStream().use {
inputStream.copyTo(it)
}
@@ -99,11 +121,17 @@ internal class FileUploader @Inject constructor(@Authenticated
}
}
- private suspend fun upload(uploadBody: RequestBody, filename: String?, progressListener: ProgressRequestBody.Listener?): ContentUploadResponse {
+ private suspend fun upload(uploadBody: RequestBody,
+ filename: String?,
+ progressListener: ProgressRequestBody.Listener?): ContentUploadResponse {
val urlBuilder = uploadUrl.toHttpUrlOrNull()?.newBuilder() ?: throw RuntimeException()
val httpUrl = urlBuilder
- .addQueryParameter("filename", filename)
+ .apply {
+ if (filename != null) {
+ addQueryParameter("filename", filename)
+ }
+ }
.build()
val requestBody = if (progressListener != null) ProgressRequestBody(uploadBody, progressListener) else uploadBody
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/ImageCompressor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/ImageCompressor.kt
index 1d6cd61060..9b01d0a00e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/ImageCompressor.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/ImageCompressor.kt
@@ -16,19 +16,20 @@
package org.matrix.android.sdk.internal.session.content
-import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Matrix
import androidx.exifinterface.media.ExifInterface
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
+import org.matrix.android.sdk.internal.util.TemporaryFileCreator
import timber.log.Timber
import java.io.File
-import java.util.UUID
import javax.inject.Inject
-internal class ImageCompressor @Inject constructor(private val context: Context) {
+internal class ImageCompressor @Inject constructor(
+ private val temporaryFileCreator: TemporaryFileCreator
+) {
suspend fun compress(
imageFile: File,
desiredWidth: Int,
@@ -45,7 +46,7 @@ internal class ImageCompressor @Inject constructor(private val context: Context)
}
} ?: return@withContext imageFile
- val destinationFile = createDestinationFile()
+ val destinationFile = temporaryFileCreator.create()
runCatching {
destinationFile.outputStream().use {
@@ -53,7 +54,7 @@ internal class ImageCompressor @Inject constructor(private val context: Context)
}
}
- return@withContext destinationFile
+ destinationFile
}
}
@@ -64,16 +65,16 @@ internal class ImageCompressor @Inject constructor(private val context: Context)
val orientation = exifInfo.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)
val matrix = Matrix()
when (orientation) {
- ExifInterface.ORIENTATION_ROTATE_270 -> matrix.postRotate(270f)
- ExifInterface.ORIENTATION_ROTATE_180 -> matrix.postRotate(180f)
- ExifInterface.ORIENTATION_ROTATE_90 -> matrix.postRotate(90f)
+ ExifInterface.ORIENTATION_ROTATE_270 -> matrix.postRotate(270f)
+ ExifInterface.ORIENTATION_ROTATE_180 -> matrix.postRotate(180f)
+ ExifInterface.ORIENTATION_ROTATE_90 -> matrix.postRotate(90f)
ExifInterface.ORIENTATION_FLIP_HORIZONTAL -> matrix.preScale(-1f, 1f)
- ExifInterface.ORIENTATION_FLIP_VERTICAL -> matrix.preScale(1f, -1f)
- ExifInterface.ORIENTATION_TRANSPOSE -> {
+ ExifInterface.ORIENTATION_FLIP_VERTICAL -> matrix.preScale(1f, -1f)
+ ExifInterface.ORIENTATION_TRANSPOSE -> {
matrix.preRotate(-90f)
matrix.preScale(-1f, 1f)
}
- ExifInterface.ORIENTATION_TRANSVERSE -> {
+ ExifInterface.ORIENTATION_TRANSVERSE -> {
matrix.preRotate(90f)
matrix.preScale(-1f, 1f)
}
@@ -116,8 +117,4 @@ internal class ImageCompressor @Inject constructor(private val context: Context)
null
}
}
-
- private fun createDestinationFile(): File {
- return File.createTempFile(UUID.randomUUID().toString(), null, context.cacheDir)
- }
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/ThumbnailExtractor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/ThumbnailExtractor.kt
index c28668a53e..82cd682eae 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/ThumbnailExtractor.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/ThumbnailExtractor.kt
@@ -23,8 +23,11 @@ import org.matrix.android.sdk.api.session.content.ContentAttachmentData
import org.matrix.android.sdk.api.util.MimeTypes
import timber.log.Timber
import java.io.ByteArrayOutputStream
+import javax.inject.Inject
-internal object ThumbnailExtractor {
+internal class ThumbnailExtractor @Inject constructor(
+ private val context: Context
+) {
class ThumbnailData(
val width: Int,
@@ -34,22 +37,22 @@ internal object ThumbnailExtractor {
val mimeType: String
)
- fun extractThumbnail(context: Context, attachment: ContentAttachmentData): ThumbnailData? {
+ fun extractThumbnail(attachment: ContentAttachmentData): ThumbnailData? {
return if (attachment.type == ContentAttachmentData.Type.VIDEO) {
- extractVideoThumbnail(context, attachment)
+ extractVideoThumbnail(attachment)
} else {
null
}
}
- private fun extractVideoThumbnail(context: Context, attachment: ContentAttachmentData): ThumbnailData? {
+ private fun extractVideoThumbnail(attachment: ContentAttachmentData): ThumbnailData? {
var thumbnailData: ThumbnailData? = null
val mediaMetadataRetriever = MediaMetadataRetriever()
try {
mediaMetadataRetriever.setDataSource(context, attachment.queryUri)
mediaMetadataRetriever.frameAtTime?.let { thumbnail ->
val outputStream = ByteArrayOutputStream()
- thumbnail.compress(Bitmap.CompressFormat.JPEG, 100, outputStream)
+ thumbnail.compress(Bitmap.CompressFormat.JPEG, 80, outputStream)
val thumbnailWidth = thumbnail.width
val thumbnailHeight = thumbnail.height
val thumbnailSize = outputStream.size()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/UploadContentWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/UploadContentWorker.kt
index 3b727690bf..237411db53 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/UploadContentWorker.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/UploadContentWorker.kt
@@ -18,9 +18,12 @@ package org.matrix.android.sdk.internal.session.content
import android.content.Context
import android.graphics.BitmapFactory
+import android.media.MediaMetadataRetriever
+import androidx.core.net.toUri
import androidx.work.WorkerParameters
import com.squareup.moshi.JsonClass
import org.matrix.android.sdk.api.extensions.tryOrNull
+import org.matrix.android.sdk.api.listeners.ProgressListener
import org.matrix.android.sdk.api.session.content.ContentAttachmentData
import org.matrix.android.sdk.api.session.events.model.toContent
import org.matrix.android.sdk.api.session.events.model.toModel
@@ -41,12 +44,13 @@ import org.matrix.android.sdk.internal.session.room.send.CancelSendTracker
import org.matrix.android.sdk.internal.session.room.send.LocalEchoIdentifiers
import org.matrix.android.sdk.internal.session.room.send.LocalEchoRepository
import org.matrix.android.sdk.internal.session.room.send.MultipleEventSendingDispatcherWorker
+import org.matrix.android.sdk.internal.util.TemporaryFileCreator
+import org.matrix.android.sdk.internal.util.toMatrixErrorStr
import org.matrix.android.sdk.internal.worker.SessionSafeCoroutineWorker
import org.matrix.android.sdk.internal.worker.SessionWorkerParams
import org.matrix.android.sdk.internal.worker.WorkerParamsFactory
import timber.log.Timber
import java.io.File
-import java.util.UUID
import javax.inject.Inject
private data class NewAttachmentAttributes(
@@ -77,7 +81,10 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter
@Inject lateinit var fileService: DefaultFileService
@Inject lateinit var cancelSendTracker: CancelSendTracker
@Inject lateinit var imageCompressor: ImageCompressor
+ @Inject lateinit var videoCompressor: VideoCompressor
+ @Inject lateinit var thumbnailExtractor: ThumbnailExtractor
@Inject lateinit var localEchoRepository: LocalEchoRepository
+ @Inject lateinit var temporaryFileCreator: TemporaryFileCreator
override fun injectWith(injector: SessionComponent) {
injector.inject(this)
@@ -109,7 +116,7 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter
val attachment = params.attachment
val filesToDelete = mutableListOf()
- try {
+ return try {
val inputStream = context.contentResolver.openInputStream(attachment.queryUri)
?: return Result.success(
WorkerParamsFactory.toData(
@@ -120,7 +127,7 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter
)
// always use a temporary file, it guaranties that we could report progress on upload and simplifies the flows
- val workingFile = File.createTempFile(UUID.randomUUID().toString(), null, context.cacheDir)
+ val workingFile = temporaryFileCreator.create()
.also { filesToDelete.add(it) }
workingFile.outputStream().use { outputStream ->
inputStream.use { inputStream ->
@@ -128,8 +135,6 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter
}
}
- val uploadThumbnailResult = dealWithThumbnail(params)
-
val progressListener = object : ProgressRequestBody.Listener {
override fun onProgress(current: Long, total: Long) {
notifyTracker(params) {
@@ -144,7 +149,7 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter
var uploadedFileEncryptedFileInfo: EncryptedFileInfo? = null
- return try {
+ try {
val fileToUpload: File
var newAttachmentAttributes = NewAttachmentAttributes(
params.attachment.width?.toInt(),
@@ -156,6 +161,8 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter
// Do not compress gif
&& attachment.mimeType != MimeTypes.Gif
&& params.compressBeforeSending) {
+ notifyTracker(params) { contentUploadStateTracker.setCompressingImage(it) }
+
fileToUpload = imageCompressor.compress(workingFile, MAX_IMAGE_SIZE, MAX_IMAGE_SIZE)
.also { compressedFile ->
// Get new Bitmap size
@@ -170,6 +177,48 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter
}
}
.also { filesToDelete.add(it) }
+ } else if (attachment.type == ContentAttachmentData.Type.VIDEO
+ // Do not compress gif
+ && attachment.mimeType != MimeTypes.Gif
+ && params.compressBeforeSending) {
+ fileToUpload = videoCompressor.compress(workingFile, object : ProgressListener {
+ override fun onProgress(progress: Int, total: Int) {
+ notifyTracker(params) { contentUploadStateTracker.setCompressingVideo(it, progress.toFloat()) }
+ }
+ })
+ .let { videoCompressionResult ->
+ when (videoCompressionResult) {
+ is VideoCompressionResult.Success -> {
+ val compressedFile = videoCompressionResult.compressedFile
+ var compressedWidth: Int? = null
+ var compressedHeight: Int? = null
+
+ tryOrNull {
+ context.contentResolver.openFileDescriptor(compressedFile.toUri(), "r")?.use { pfd ->
+ MediaMetadataRetriever().let {
+ it.setDataSource(pfd.fileDescriptor)
+ compressedWidth = it.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH)?.toInt()
+ compressedHeight = it.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT)?.toInt()
+ }
+ }
+ }
+
+ // Get new Video file size and dimensions
+ newAttachmentAttributes = newAttachmentAttributes.copy(
+ newFileSize = compressedFile.length(),
+ newWidth = compressedWidth ?: newAttachmentAttributes.newWidth,
+ newHeight = compressedHeight ?: newAttachmentAttributes.newHeight
+ )
+ compressedFile
+ .also { filesToDelete.add(it) }
+ }
+ VideoCompressionResult.CompressionNotNeeded,
+ VideoCompressionResult.CompressionCancelled,
+ is VideoCompressionResult.CompressionFailed -> {
+ workingFile
+ }
+ }
+ }
} else {
fileToUpload = workingFile
// Fix: OpenableColumns.SIZE may return -1 or 0
@@ -180,9 +229,8 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter
val encryptedFile: File?
val contentUploadResponse = if (params.isEncrypted) {
- Timber.v("## FileService: Encrypt file")
-
- encryptedFile = File.createTempFile(UUID.randomUUID().toString(), null, context.cacheDir)
+ Timber.v("## Encrypt file")
+ encryptedFile = temporaryFileCreator.create()
.also { filesToDelete.add(it) }
uploadedFileEncryptedFileInfo =
@@ -191,19 +239,25 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter
contentUploadStateTracker.setEncrypting(it, read.toLong(), total.toLong())
}
}
-
- Timber.v("## FileService: Uploading file")
-
- fileUploader
- .uploadFile(encryptedFile, attachment.name, MimeTypes.OctetStream, progressListener)
+ Timber.v("## Uploading file")
+ fileUploader.uploadFile(
+ file = encryptedFile,
+ filename = null,
+ mimeType = MimeTypes.OctetStream,
+ progressListener = progressListener
+ )
} else {
- Timber.v("## FileService: Clear file")
+ Timber.v("## Uploading clear file")
encryptedFile = null
- fileUploader
- .uploadFile(fileToUpload, attachment.name, attachment.getSafeMimeType(), progressListener)
+ fileUploader.uploadFile(
+ file = fileToUpload,
+ filename = attachment.name,
+ mimeType = attachment.getSafeMimeType(),
+ progressListener = progressListener
+ )
}
- Timber.v("## FileService: Update cache storage for ${contentUploadResponse.contentUri}")
+ Timber.v("## Update cache storage for ${contentUploadResponse.contentUri}")
try {
fileService.storeDataFor(
mxcUrl = contentUploadResponse.contentUri,
@@ -212,11 +266,13 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter
originalFile = workingFile,
encryptedFile = encryptedFile
)
- Timber.v("## FileService: cache storage updated")
+ Timber.v("## cache storage updated")
} catch (failure: Throwable) {
- Timber.e(failure, "## FileService: Failed to update file cache")
+ Timber.e(failure, "## Failed to update file cache")
}
+ val uploadThumbnailResult = dealWithThumbnail(params)
+
handleSuccess(params,
contentUploadResponse.contentUri,
uploadedFileEncryptedFileInfo,
@@ -224,12 +280,12 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter
uploadThumbnailResult?.uploadedThumbnailEncryptedFileInfo,
newAttachmentAttributes)
} catch (t: Throwable) {
- Timber.e(t, "## FileService: ERROR ${t.localizedMessage}")
+ Timber.e(t, "## ERROR ${t.localizedMessage}")
handleFailure(params, t)
}
} catch (e: Exception) {
- Timber.e(e, "## FileService: ERROR")
- return handleFailure(params, e)
+ Timber.e(e, "## ERROR")
+ handleFailure(params, e)
} finally {
// Delete all temporary files
filesToDelete.forEach {
@@ -247,7 +303,7 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter
* If appropriate, it will create and upload a thumbnail
*/
private suspend fun dealWithThumbnail(params: Params): UploadThumbnailResult? {
- return ThumbnailExtractor.extractThumbnail(context, params.attachment)
+ return thumbnailExtractor.extractThumbnail(params.attachment)
?.let { thumbnailData ->
val thumbnailProgressListener = object : ProgressRequestBody.Listener {
override fun onProgress(current: Long, total: Long) {
@@ -260,19 +316,23 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter
Timber.v("Encrypt thumbnail")
notifyTracker(params) { contentUploadStateTracker.setEncryptingThumbnail(it) }
val encryptionResult = MXEncryptedAttachments.encryptAttachment(thumbnailData.bytes.inputStream(), thumbnailData.mimeType)
- val contentUploadResponse = fileUploader.uploadByteArray(encryptionResult.encryptedByteArray,
- "thumb_${params.attachment.name}",
- MimeTypes.OctetStream,
- thumbnailProgressListener)
+ val contentUploadResponse = fileUploader.uploadByteArray(
+ byteArray = encryptionResult.encryptedByteArray,
+ filename = null,
+ mimeType = MimeTypes.OctetStream,
+ progressListener = thumbnailProgressListener
+ )
UploadThumbnailResult(
contentUploadResponse.contentUri,
encryptionResult.encryptedFileInfo
)
} else {
- val contentUploadResponse = fileUploader.uploadByteArray(thumbnailData.bytes,
- "thumb_${params.attachment.name}",
- thumbnailData.mimeType,
- thumbnailProgressListener)
+ val contentUploadResponse = fileUploader.uploadByteArray(
+ byteArray = thumbnailData.bytes,
+ filename = "thumb_${params.attachment.name}",
+ mimeType = thumbnailData.mimeType,
+ progressListener = thumbnailProgressListener
+ )
UploadThumbnailResult(
contentUploadResponse.contentUri,
null
@@ -291,7 +351,7 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter
return Result.success(
WorkerParamsFactory.toData(
params.copy(
- lastFailureMessage = failure.localizedMessage
+ lastFailureMessage = failure.toMatrixErrorStr()
)
)
)
@@ -328,8 +388,7 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter
val messageContent: MessageContent? = event.asDomain().content.toModel()
val updatedContent = when (messageContent) {
is MessageImageContent -> messageContent.update(url, encryptedFileInfo, newAttachmentAttributes)
- is MessageVideoContent -> messageContent.update(url, encryptedFileInfo, thumbnailUrl, thumbnailEncryptedFileInfo,
- newAttachmentAttributes.newFileSize)
+ is MessageVideoContent -> messageContent.update(url, encryptedFileInfo, thumbnailUrl, thumbnailEncryptedFileInfo, newAttachmentAttributes)
is MessageFileContent -> messageContent.update(url, encryptedFileInfo, newAttachmentAttributes.newFileSize)
is MessageAudioContent -> messageContent.update(url, encryptedFileInfo, newAttachmentAttributes.newFileSize)
else -> messageContent
@@ -351,7 +410,7 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter
info = info?.copy(
width = newAttachmentAttributes?.newWidth ?: info.width,
height = newAttachmentAttributes?.newHeight ?: info.height,
- size = newAttachmentAttributes?.newFileSize?.toInt() ?: info.size
+ size = newAttachmentAttributes?.newFileSize ?: info.size
)
)
}
@@ -360,14 +419,16 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter
encryptedFileInfo: EncryptedFileInfo?,
thumbnailUrl: String?,
thumbnailEncryptedFileInfo: EncryptedFileInfo?,
- size: Long): MessageVideoContent {
+ newAttachmentAttributes: NewAttachmentAttributes?): MessageVideoContent {
return copy(
url = if (encryptedFileInfo == null) url else null,
encryptedFileInfo = encryptedFileInfo?.copy(url = url),
videoInfo = videoInfo?.copy(
thumbnailUrl = if (thumbnailEncryptedFileInfo == null) thumbnailUrl else null,
thumbnailFile = thumbnailEncryptedFileInfo?.copy(url = thumbnailUrl),
- size = size
+ width = newAttachmentAttributes?.newWidth ?: videoInfo.width,
+ height = newAttachmentAttributes?.newHeight ?: videoInfo.height,
+ size = newAttachmentAttributes?.newFileSize ?: videoInfo.size
)
)
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/VideoCompressionResult.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/VideoCompressionResult.kt
new file mode 100644
index 0000000000..87d5c7e6a3
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/VideoCompressionResult.kt
@@ -0,0 +1,26 @@
+/*
+ * 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.internal.session.content
+
+import java.io.File
+
+internal sealed class VideoCompressionResult {
+ data class Success(val compressedFile: File) : VideoCompressionResult()
+ object CompressionNotNeeded : VideoCompressionResult()
+ object CompressionCancelled : VideoCompressionResult()
+ data class CompressionFailed(val failure: Throwable) : VideoCompressionResult()
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/VideoCompressor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/VideoCompressor.kt
new file mode 100644
index 0000000000..05aaf4e9f1
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/VideoCompressor.kt
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2021 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.internal.session.content
+
+import com.otaliastudios.transcoder.Transcoder
+import com.otaliastudios.transcoder.TranscoderListener
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.withContext
+import org.matrix.android.sdk.api.listeners.ProgressListener
+import org.matrix.android.sdk.internal.util.TemporaryFileCreator
+import timber.log.Timber
+import java.io.File
+import javax.inject.Inject
+
+internal class VideoCompressor @Inject constructor(
+ private val temporaryFileCreator: TemporaryFileCreator
+) {
+
+ suspend fun compress(videoFile: File,
+ progressListener: ProgressListener?): VideoCompressionResult {
+ val destinationFile = temporaryFileCreator.create()
+
+ val job = Job()
+
+ Timber.d("Compressing: start")
+ progressListener?.onProgress(0, 100)
+
+ var result: Int = -1
+ var failure: Throwable? = null
+ Transcoder.into(destinationFile.path)
+ .addDataSource(videoFile.path)
+ .setListener(object : TranscoderListener {
+ override fun onTranscodeProgress(progress: Double) {
+ Timber.d("Compressing: $progress%")
+ progressListener?.onProgress((progress * 100).toInt(), 100)
+ }
+
+ override fun onTranscodeCompleted(successCode: Int) {
+ Timber.d("Compressing: success: $successCode")
+ result = successCode
+ job.complete()
+ }
+
+ override fun onTranscodeCanceled() {
+ Timber.d("Compressing: cancel")
+ job.cancel()
+ }
+
+ override fun onTranscodeFailed(exception: Throwable) {
+ Timber.w(exception, "Compressing: failure")
+ failure = exception
+ job.completeExceptionally(exception)
+ }
+ })
+ .transcode()
+
+ job.join()
+
+ // Note: job is also cancelled if completeExceptionally() was called
+ if (job.isCancelled) {
+ // Delete now the temporary file
+ deleteFile(destinationFile)
+ return when (val finalFailure = failure) {
+ null -> {
+ // We do not throw a CancellationException, because it's not critical, we will try to send the original file
+ // Anyway this should never occurs, since we never cancel the return value of transcode()
+ Timber.w("Compressing: A failure occurred")
+ VideoCompressionResult.CompressionCancelled
+ }
+ else -> {
+ // Compression failure can also be considered as not critical, but let the caller decide
+ Timber.w("Compressing: Job cancelled")
+ VideoCompressionResult.CompressionFailed(finalFailure)
+ }
+ }
+ }
+
+ progressListener?.onProgress(100, 100)
+
+ return when (result) {
+ Transcoder.SUCCESS_TRANSCODED -> {
+ VideoCompressionResult.Success(destinationFile)
+ }
+ Transcoder.SUCCESS_NOT_NEEDED -> {
+ // Delete now the temporary file
+ deleteFile(destinationFile)
+ VideoCompressionResult.CompressionNotNeeded
+ }
+ else -> {
+ // Should not happen...
+ // Delete now the temporary file
+ deleteFile(destinationFile)
+ Timber.w("Unknown result: $result")
+ VideoCompressionResult.CompressionFailed(IllegalStateException("Unknown result: $result"))
+ }
+ }
+ }
+
+ private suspend fun deleteFile(file: File) {
+ withContext(Dispatchers.IO) {
+ file.delete()
+ }
+ }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/DefaultIdentityService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/DefaultIdentityService.kt
index f5391d6cdb..4f88d8eb95 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/DefaultIdentityService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/DefaultIdentityService.kt
@@ -36,7 +36,7 @@ import org.matrix.android.sdk.internal.di.AuthenticatedIdentity
import org.matrix.android.sdk.internal.di.UnauthenticatedWithCertificate
import org.matrix.android.sdk.internal.extensions.observeNotNull
import org.matrix.android.sdk.internal.network.RetrofitFactory
-import org.matrix.android.sdk.internal.session.SessionLifecycleObserver
+import org.matrix.android.sdk.api.session.SessionLifecycleObserver
import org.matrix.android.sdk.internal.session.SessionScope
import org.matrix.android.sdk.internal.session.identity.data.IdentityStore
import org.matrix.android.sdk.internal.session.openid.GetOpenIdTokenTask
@@ -44,13 +44,14 @@ import org.matrix.android.sdk.internal.session.profile.BindThreePidsTask
import org.matrix.android.sdk.internal.session.profile.UnbindThreePidsTask
import org.matrix.android.sdk.internal.session.sync.model.accountdata.IdentityServerContent
import org.matrix.android.sdk.api.session.accountdata.UserAccountDataTypes
-import org.matrix.android.sdk.internal.session.user.accountdata.AccountDataDataSource
+import org.matrix.android.sdk.internal.session.user.accountdata.UserAccountDataDataSource
import org.matrix.android.sdk.internal.session.user.accountdata.UpdateUserAccountDataTask
import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers
import org.matrix.android.sdk.internal.util.ensureProtocol
import kotlinx.coroutines.withContext
import okhttp3.OkHttpClient
import org.matrix.android.sdk.api.extensions.orFalse
+import org.matrix.android.sdk.api.session.Session
import timber.log.Timber
import javax.inject.Inject
import javax.net.ssl.HttpsURLConnection
@@ -76,7 +77,7 @@ internal class DefaultIdentityService @Inject constructor(
private val submitTokenForBindingTask: IdentitySubmitTokenForBindingTask,
private val unbindThreePidsTask: UnbindThreePidsTask,
private val identityApiProvider: IdentityApiProvider,
- private val accountDataDataSource: AccountDataDataSource,
+ private val accountDataDataSource: UserAccountDataDataSource,
private val homeServerCapabilitiesService: HomeServerCapabilitiesService,
private val sessionParams: SessionParams
) : IdentityService, SessionLifecycleObserver {
@@ -86,7 +87,7 @@ internal class DefaultIdentityService @Inject constructor(
private val listeners = mutableSetOf()
- override fun onSessionStarted() {
+ override fun onSessionStarted(session: Session) {
lifecycleRegistry.currentState = Lifecycle.State.STARTED
// Observe the account data change
accountDataDataSource
@@ -111,7 +112,7 @@ internal class DefaultIdentityService @Inject constructor(
}
}
- override fun onSessionStopped() {
+ override fun onSessionStopped(session: Session) {
lifecycleRegistry.currentState = Lifecycle.State.DESTROYED
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityAuthAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityAuthAPI.kt
index 1671859585..9d990d4d8f 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityAuthAPI.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityAuthAPI.kt
@@ -16,9 +16,9 @@
package org.matrix.android.sdk.internal.session.identity
+import org.matrix.android.sdk.api.session.openid.OpenIdToken
import org.matrix.android.sdk.internal.network.NetworkConstants
import org.matrix.android.sdk.internal.session.identity.model.IdentityRegisterResponse
-import org.matrix.android.sdk.internal.session.openid.RequestOpenIdTokenResponse
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.POST
@@ -52,5 +52,5 @@ internal interface IdentityAuthAPI {
* The request body is the same as the values returned by /openid/request_token in the Client-Server API.
*/
@POST(NetworkConstants.URI_IDENTITY_PATH_V2 + "account/register")
- suspend fun register(@Body openIdToken: RequestOpenIdTokenResponse): IdentityRegisterResponse
+ suspend fun register(@Body openIdToken: OpenIdToken): IdentityRegisterResponse
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityBulkLookupTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityBulkLookupTask.kt
index 4f6e906766..114695062c 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityBulkLookupTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityBulkLookupTask.kt
@@ -117,7 +117,7 @@ internal class DefaultIdentityBulkLookupTask @Inject constructor(
return withOlmUtility { olmUtility ->
threePids.map { threePid ->
base64ToBase64Url(
- olmUtility.sha256(threePid.value.toLowerCase(Locale.ROOT)
+ olmUtility.sha256(threePid.value.lowercase(Locale.ROOT)
+ " " + threePid.toMedium() + " " + pepper)
)
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityRegisterTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityRegisterTask.kt
index 8cc854bd94..1800d0eebe 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityRegisterTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityRegisterTask.kt
@@ -16,16 +16,16 @@
package org.matrix.android.sdk.internal.session.identity
+import org.matrix.android.sdk.api.session.openid.OpenIdToken
import org.matrix.android.sdk.internal.network.executeRequest
import org.matrix.android.sdk.internal.session.identity.model.IdentityRegisterResponse
-import org.matrix.android.sdk.internal.session.openid.RequestOpenIdTokenResponse
import org.matrix.android.sdk.internal.task.Task
import javax.inject.Inject
internal interface IdentityRegisterTask : Task {
data class Params(
val identityAuthAPI: IdentityAuthAPI,
- val openIdTokenResponse: RequestOpenIdTokenResponse
+ val openIdToken: OpenIdToken
)
}
@@ -33,7 +33,7 @@ internal class DefaultIdentityRegisterTask @Inject constructor() : IdentityRegis
override suspend fun execute(params: IdentityRegisterTask.Params): IdentityRegisterResponse {
return executeRequest(null) {
- params.identityAuthAPI.register(params.openIdTokenResponse)
+ params.identityAuthAPI.register(params.openIdToken)
}
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/integrationmanager/IntegrationManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/integrationmanager/IntegrationManager.kt
index e34615d269..aa82cf9222 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/integrationmanager/IntegrationManager.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/integrationmanager/IntegrationManager.kt
@@ -21,6 +21,7 @@ import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LifecycleRegistry
import com.zhuinden.monarchy.Monarchy
import org.matrix.android.sdk.api.MatrixConfiguration
+import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.integrationmanager.IntegrationManagerConfig
import org.matrix.android.sdk.api.session.integrationmanager.IntegrationManagerService
@@ -29,11 +30,11 @@ import org.matrix.android.sdk.api.session.widgets.model.WidgetType
import org.matrix.android.sdk.internal.database.model.WellknownIntegrationManagerConfigEntity
import org.matrix.android.sdk.internal.di.SessionDatabase
import org.matrix.android.sdk.internal.extensions.observeNotNull
-import org.matrix.android.sdk.internal.session.SessionLifecycleObserver
+import org.matrix.android.sdk.api.session.SessionLifecycleObserver
import org.matrix.android.sdk.internal.session.SessionScope
import org.matrix.android.sdk.api.session.accountdata.UserAccountDataTypes
import org.matrix.android.sdk.api.session.accountdata.UserAccountDataEvent
-import org.matrix.android.sdk.internal.session.user.accountdata.AccountDataDataSource
+import org.matrix.android.sdk.internal.session.user.accountdata.UserAccountDataDataSource
import org.matrix.android.sdk.internal.session.user.accountdata.UpdateUserAccountDataTask
import org.matrix.android.sdk.internal.session.widgets.helper.WidgetFactory
import org.matrix.android.sdk.internal.session.widgets.helper.extractWidgetSequence
@@ -56,7 +57,7 @@ import javax.inject.Inject
internal class IntegrationManager @Inject constructor(matrixConfiguration: MatrixConfiguration,
@SessionDatabase private val monarchy: Monarchy,
private val updateUserAccountDataTask: UpdateUserAccountDataTask,
- private val accountDataDataSource: AccountDataDataSource,
+ private val accountDataDataSource: UserAccountDataDataSource,
private val widgetFactory: WidgetFactory)
: SessionLifecycleObserver {
@@ -77,7 +78,7 @@ internal class IntegrationManager @Inject constructor(matrixConfiguration: Matri
currentConfigs.add(defaultConfig)
}
- override fun onSessionStarted() {
+ override fun onSessionStarted(session: Session) {
lifecycleRegistry.currentState = Lifecycle.State.STARTED
observeWellknownConfig()
accountDataDataSource
@@ -105,7 +106,7 @@ internal class IntegrationManager @Inject constructor(matrixConfiguration: Matri
}
}
- override fun onSessionStopped() {
+ override fun onSessionStopped(session: Session) {
lifecycleRegistry.currentState = Lifecycle.State.DESTROYED
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/openid/DefaultOpenIdService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/openid/DefaultOpenIdService.kt
new file mode 100644
index 0000000000..b90a2435f7
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/openid/DefaultOpenIdService.kt
@@ -0,0 +1,28 @@
+/*
+ * 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.internal.session.openid
+
+import org.matrix.android.sdk.api.session.openid.OpenIdService
+import org.matrix.android.sdk.api.session.openid.OpenIdToken
+import javax.inject.Inject
+
+internal class DefaultOpenIdService @Inject constructor(private val getOpenIdTokenTask: GetOpenIdTokenTask): OpenIdService {
+
+ override suspend fun getOpenIdToken(): OpenIdToken {
+ return getOpenIdTokenTask.execute(Unit)
+ }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/openid/GetOpenIdTokenTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/openid/GetOpenIdTokenTask.kt
index 8481a6ab93..a6ad025b8d 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/openid/GetOpenIdTokenTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/openid/GetOpenIdTokenTask.kt
@@ -16,20 +16,21 @@
package org.matrix.android.sdk.internal.session.openid
+import org.matrix.android.sdk.api.session.openid.OpenIdToken
import org.matrix.android.sdk.internal.di.UserId
import org.matrix.android.sdk.internal.network.GlobalErrorReceiver
import org.matrix.android.sdk.internal.network.executeRequest
import org.matrix.android.sdk.internal.task.Task
import javax.inject.Inject
-internal interface GetOpenIdTokenTask : Task
+internal interface GetOpenIdTokenTask : Task
internal class DefaultGetOpenIdTokenTask @Inject constructor(
@UserId private val userId: String,
private val openIdAPI: OpenIdAPI,
private val globalErrorReceiver: GlobalErrorReceiver) : GetOpenIdTokenTask {
- override suspend fun execute(params: Unit): RequestOpenIdTokenResponse {
+ override suspend fun execute(params: Unit): OpenIdToken {
return executeRequest(globalErrorReceiver) {
openIdAPI.openIdToken(userId)
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/openid/OpenIdAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/openid/OpenIdAPI.kt
index ed090b845d..eb8c841d57 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/openid/OpenIdAPI.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/openid/OpenIdAPI.kt
@@ -16,6 +16,7 @@
package org.matrix.android.sdk.internal.session.openid
+import org.matrix.android.sdk.api.session.openid.OpenIdToken
import org.matrix.android.sdk.api.util.JsonDict
import org.matrix.android.sdk.internal.network.NetworkConstants
import retrofit2.http.Body
@@ -34,5 +35,5 @@ internal interface OpenIdAPI {
*/
@POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "user/{userId}/openid/request_token")
suspend fun openIdToken(@Path("userId") userId: String,
- @Body body: JsonDict = emptyMap()): RequestOpenIdTokenResponse
+ @Body body: JsonDict = emptyMap()): OpenIdToken
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/DefaultPermalinkService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/DefaultPermalinkService.kt
index 7db9d8f68a..134da4ce51 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/DefaultPermalinkService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/DefaultPermalinkService.kt
@@ -33,8 +33,8 @@ internal class DefaultPermalinkService @Inject constructor(
return permalinkFactory.createPermalink(id)
}
- override fun createRoomPermalink(roomId: String): String? {
- return permalinkFactory.createRoomPermalink(roomId)
+ override fun createRoomPermalink(roomId: String, viaServers: List?): String? {
+ return permalinkFactory.createRoomPermalink(roomId, viaServers)
}
override fun createPermalink(roomId: String, eventId: String): String {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/PermalinkFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/PermalinkFactory.kt
index 71a6e224bf..639e45582a 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/PermalinkFactory.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/PermalinkFactory.kt
@@ -18,19 +18,13 @@ package org.matrix.android.sdk.internal.session.permalinks
import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.permalinks.PermalinkService.Companion.MATRIX_TO_URL_BASE
-import org.matrix.android.sdk.api.session.room.members.roomMemberQueryParams
-import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.internal.di.UserId
-import org.matrix.android.sdk.internal.session.room.RoomGetter
-import java.net.URLEncoder
import javax.inject.Inject
-import javax.inject.Provider
internal class PermalinkFactory @Inject constructor(
@UserId
private val userId: String,
- // Use a provider to fix circular Dagger dependency
- private val roomGetterProvider: Provider
+ private val viaParameterFinder: ViaParameterFinder
) {
fun createPermalink(event: Event): String? {
@@ -46,16 +40,23 @@ internal class PermalinkFactory @Inject constructor(
} else MATRIX_TO_URL_BASE + escape(id)
}
- fun createRoomPermalink(roomId: String): String? {
+ fun createRoomPermalink(roomId: String, via: List? = null): String? {
return if (roomId.isEmpty()) {
null
} else {
- MATRIX_TO_URL_BASE + escape(roomId) + computeViaParams(userId, roomId)
+ buildString {
+ append(MATRIX_TO_URL_BASE)
+ append(escape(roomId))
+ append(
+ via?.takeIf { it.isNotEmpty() }?.let { viaParameterFinder.asUrlViaParameters(it) }
+ ?: viaParameterFinder.computeViaParams(userId, roomId)
+ )
+ }
}
}
fun createPermalink(roomId: String, eventId: String): String {
- return MATRIX_TO_URL_BASE + escape(roomId) + "/" + escape(eventId) + computeViaParams(userId, roomId)
+ return MATRIX_TO_URL_BASE + escape(roomId) + "/" + escape(eventId) + viaParameterFinder.computeViaParams(userId, roomId)
}
fun getLinkedId(url: String): String? {
@@ -66,25 +67,6 @@ internal class PermalinkFactory @Inject constructor(
} else null
}
- /**
- * Compute the via parameters.
- * Take up to 3 homeserver domains, taking the most representative one regarding room members and including the
- * current user one.
- */
- private fun computeViaParams(userId: String, roomId: String): String {
- val userHomeserver = userId.substringAfter(":")
- return getUserIdsOfJoinedMembers(roomId)
- .map { it.substringAfter(":") }
- .groupBy { it }
- .mapValues { it.value.size }
- .toMutableMap()
- // Ensure the user homeserver will be included
- .apply { this[userHomeserver] = Int.MAX_VALUE }
- .let { map -> map.keys.sortedByDescending { map[it] } }
- .take(3)
- .joinToString(prefix = "?via=", separator = "&via=") { URLEncoder.encode(it, "utf-8") }
- }
-
/**
* Escape '/' in id, because it is used as a separator
*
@@ -104,15 +86,4 @@ internal class PermalinkFactory @Inject constructor(
private fun unescape(id: String): String {
return id.replace("%2F", "/")
}
-
- /**
- * Get a set of userIds of joined members of a room
- */
- private fun getUserIdsOfJoinedMembers(roomId: String): Set {
- return roomGetterProvider.get().getRoom(roomId)
- ?.getRoomMembers(roomMemberQueryParams { memberships = listOf(Membership.JOIN) })
- ?.map { it.userId }
- .orEmpty()
- .toSet()
- }
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/ViaParameterFinder.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/ViaParameterFinder.kt
new file mode 100644
index 0000000000..72fbfcced5
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/ViaParameterFinder.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2021 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.internal.session.permalinks
+
+import org.matrix.android.sdk.api.session.room.members.roomMemberQueryParams
+import org.matrix.android.sdk.api.session.room.model.Membership
+import org.matrix.android.sdk.internal.di.UserId
+import org.matrix.android.sdk.internal.session.room.RoomGetter
+import java.net.URLEncoder
+import javax.inject.Inject
+import javax.inject.Provider
+
+internal class ViaParameterFinder @Inject constructor(
+ @UserId private val userId: String,
+ private val roomGetterProvider: Provider
+) {
+
+ fun computeViaParams(roomId: String, max: Int): List {
+ return computeViaParams(userId, roomId, max)
+ }
+
+ /**
+ * Compute the via parameters.
+ * Take up to 3 homeserver domains, taking the most representative one regarding room members and including the
+ * current user one.
+ */
+ fun computeViaParams(userId: String, roomId: String): String {
+ return asUrlViaParameters(computeViaParams(userId, roomId, 3))
+ }
+
+ fun asUrlViaParameters(viaList: List): String {
+ return viaList.joinToString(prefix = "?via=", separator = "&via=") { URLEncoder.encode(it, "utf-8") }
+ }
+
+ fun computeViaParams(userId: String, roomId: String, max: Int): List {
+ val userHomeserver = userId.substringAfter(":")
+ return getUserIdsOfJoinedMembers(roomId)
+ .map { it.substringAfter(":") }
+ .groupBy { it }
+ .mapValues { it.value.size }
+ .toMutableMap()
+ // Ensure the user homeserver will be included
+ .apply { this[userHomeserver] = Int.MAX_VALUE }
+ .let { map -> map.keys.sortedByDescending { map[it] } }
+ .take(max)
+ }
+
+ /**
+ * Get a set of userIds of joined members of a room
+ */
+ private fun getUserIdsOfJoinedMembers(roomId: String): Set {
+ return roomGetterProvider.get().getRoom(roomId)
+ ?.getRoomMembers(roomMemberQueryParams { memberships = listOf(Membership.JOIN) })
+ ?.map { it.userId }
+ .orEmpty()
+ .toSet()
+ }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/ProfileAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/ProfileAPI.kt
index 5113b821e8..485a4973ca 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/ProfileAPI.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/ProfileAPI.kt
@@ -33,6 +33,7 @@ internal interface ProfileAPI {
* Get the combined profile information for this user.
* This API may be used to fetch the user's own profile information or other users; either locally or on remote homeservers.
* This API may return keys which are not limited to displayname or avatar_url.
+ * If server is configured as limit_profile_requests_to_users_who_share_rooms: true then response can be HTTP 403.
* @param userId the user id to fetch profile info
*/
@GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "profile/{userId}")
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoom.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoom.kt
index 1d8eb6c95e..0d9c106d41 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoom.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoom.kt
@@ -20,10 +20,12 @@ import androidx.lifecycle.LiveData
import org.matrix.android.sdk.api.session.crypto.CryptoService
import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.room.Room
+import org.matrix.android.sdk.api.session.room.accountdata.RoomAccountDataService
import org.matrix.android.sdk.api.session.room.alias.AliasService
import org.matrix.android.sdk.api.session.room.call.RoomCallService
import org.matrix.android.sdk.api.session.room.members.MembershipService
import org.matrix.android.sdk.api.session.room.model.RoomSummary
+import org.matrix.android.sdk.api.session.room.model.RoomType
import org.matrix.android.sdk.api.session.room.model.relation.RelationService
import org.matrix.android.sdk.api.session.room.notification.RoomPushRuleService
import org.matrix.android.sdk.api.session.room.read.ReadService
@@ -36,34 +38,38 @@ import org.matrix.android.sdk.api.session.room.timeline.TimelineService
import org.matrix.android.sdk.api.session.room.typing.TypingService
import org.matrix.android.sdk.api.session.room.uploads.UploadsService
import org.matrix.android.sdk.api.session.search.SearchResult
+import org.matrix.android.sdk.api.session.space.Space
import org.matrix.android.sdk.api.util.Optional
import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM
+import org.matrix.android.sdk.internal.session.permalinks.ViaParameterFinder
import org.matrix.android.sdk.internal.session.room.state.SendStateTask
import org.matrix.android.sdk.internal.session.room.summary.RoomSummaryDataSource
import org.matrix.android.sdk.internal.session.search.SearchTask
+import org.matrix.android.sdk.internal.session.space.DefaultSpace
import org.matrix.android.sdk.internal.util.awaitCallback
import java.security.InvalidParameterException
-import javax.inject.Inject
-internal class DefaultRoom @Inject constructor(override val roomId: String,
- private val roomSummaryDataSource: RoomSummaryDataSource,
- private val timelineService: TimelineService,
- private val sendService: SendService,
- private val draftService: DraftService,
- private val stateService: StateService,
- private val uploadsService: UploadsService,
- private val reportingService: ReportingService,
- private val roomCallService: RoomCallService,
- private val readService: ReadService,
- private val typingService: TypingService,
- private val aliasService: AliasService,
- private val tagsService: TagsService,
- private val cryptoService: CryptoService,
- private val relationService: RelationService,
- private val roomMembersService: MembershipService,
- private val roomPushRuleService: RoomPushRuleService,
- private val sendStateTask: SendStateTask,
- private val searchTask: SearchTask) :
+internal class DefaultRoom(override val roomId: String,
+ private val roomSummaryDataSource: RoomSummaryDataSource,
+ private val timelineService: TimelineService,
+ private val sendService: SendService,
+ private val draftService: DraftService,
+ private val stateService: StateService,
+ private val uploadsService: UploadsService,
+ private val reportingService: ReportingService,
+ private val roomCallService: RoomCallService,
+ private val readService: ReadService,
+ private val typingService: TypingService,
+ private val aliasService: AliasService,
+ private val tagsService: TagsService,
+ private val cryptoService: CryptoService,
+ private val relationService: RelationService,
+ private val roomMembersService: MembershipService,
+ private val roomPushRuleService: RoomPushRuleService,
+ private val roomAccountDataService: RoomAccountDataService,
+ private val sendStateTask: SendStateTask,
+ private val viaParameterFinder: ViaParameterFinder,
+ private val searchTask: SearchTask) :
Room,
TimelineService by timelineService,
SendService by sendService,
@@ -78,7 +84,8 @@ internal class DefaultRoom @Inject constructor(override val roomId: String,
TagsService by tagsService,
RelationService by relationService,
MembershipService by roomMembersService,
- RoomPushRuleService by roomPushRuleService {
+ RoomPushRuleService by roomPushRuleService,
+ RoomAccountDataService by roomAccountDataService {
override fun getRoomSummaryLive(): LiveData> {
return roomSummaryDataSource.getRoomSummaryLive(roomId)
@@ -148,4 +155,9 @@ internal class DefaultRoom @Inject constructor(override val roomId: String,
)
)
}
+
+ override fun asSpace(): Space? {
+ if (roomSummary()?.roomType != RoomType.SPACE) return null
+ return DefaultSpace(this, roomSummaryDataSource, viaParameterFinder)
+ }
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoomService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoomService.kt
index 22f61bc517..d9fe1288e2 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoomService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoomService.kt
@@ -23,9 +23,11 @@ import com.zhuinden.monarchy.Monarchy
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.RoomService
+import org.matrix.android.sdk.api.session.room.RoomSortOrder
import org.matrix.android.sdk.api.session.room.RoomSummaryQueryParams
-import org.matrix.android.sdk.api.session.room.UpdatableFilterLivePageResult
+import org.matrix.android.sdk.api.session.room.UpdatableLivePageResult
import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
+import org.matrix.android.sdk.api.session.room.model.Membership
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.create.CreateRoomParams
@@ -67,7 +69,7 @@ internal class DefaultRoomService @Inject constructor(
) : RoomService {
override suspend fun createRoom(createRoomParams: CreateRoomParams): String {
- return createRoomTask.execute(createRoomParams)
+ return createRoomTask.executeRetry(createRoomParams, 3)
}
override fun getRoom(roomId: String): Room? {
@@ -90,14 +92,14 @@ internal class DefaultRoomService @Inject constructor(
return roomSummaryDataSource.getRoomSummariesLive(queryParams)
}
- override fun getPagedRoomSummariesLive(queryParams: RoomSummaryQueryParams, pagedListConfig: PagedList.Config)
+ override fun getPagedRoomSummariesLive(queryParams: RoomSummaryQueryParams, pagedListConfig: PagedList.Config, sortOrder: RoomSortOrder)
: LiveData> {
- return roomSummaryDataSource.getSortedPagedRoomSummariesLive(queryParams, pagedListConfig)
+ return roomSummaryDataSource.getSortedPagedRoomSummariesLive(queryParams, pagedListConfig, sortOrder)
}
- override fun getFilteredPagedRoomSummariesLive(queryParams: RoomSummaryQueryParams, pagedListConfig: PagedList.Config)
- : UpdatableFilterLivePageResult {
- return roomSummaryDataSource.getFilteredPagedRoomSummariesLive(queryParams, pagedListConfig)
+ override fun getFilteredPagedRoomSummariesLive(queryParams: RoomSummaryQueryParams, pagedListConfig: PagedList.Config, sortOrder: RoomSortOrder)
+ : UpdatableLivePageResult {
+ return roomSummaryDataSource.getUpdatablePagedRoomSummariesLive(queryParams, pagedListConfig, sortOrder)
}
override fun getNotificationCountForRooms(queryParams: RoomSummaryQueryParams): RoomAggregateNotificationCount {
@@ -163,4 +165,18 @@ internal class DefaultRoomService @Inject constructor(
override suspend fun peekRoom(roomIdOrAlias: String): PeekResult {
return peekRoomTask.execute(PeekRoomTask.Params(roomIdOrAlias))
}
+
+ override fun getFlattenRoomSummaryChildrenOf(spaceId: String?, memberships: List): List {
+ if (spaceId == null) {
+ return roomSummaryDataSource.getFlattenOrphanRooms()
+ }
+ return roomSummaryDataSource.getAllRoomSummaryChildOf(spaceId, memberships)
+ }
+
+ override fun getFlattenRoomSummaryChildrenOfLive(spaceId: String?, memberships: List): LiveData> {
+ if (spaceId == null) {
+ return roomSummaryDataSource.getFlattenOrphanRoomsLive()
+ }
+ return roomSummaryDataSource.getAllRoomSummaryChildOfLive(spaceId, memberships)
+ }
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt
index 6fee630510..4f12604039 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt
@@ -360,4 +360,13 @@ internal interface RoomAPI {
suspend fun deleteTag(@Path("userId") userId: String,
@Path("roomId") roomId: String,
@Path("tag") tag: String)
+
+ /**
+ * Set an AccountData event to the room.
+ */
+ @PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "user/{userId}/rooms/{roomId}/account_data/{type}")
+ suspend fun setRoomAccountData(@Path("userId") userId: String,
+ @Path("roomId") roomId: String,
+ @Path("type") type: String,
+ @Body content: JsonDict)
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomFactory.kt
index 90640b4700..9ddb8f1177 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomFactory.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomFactory.kt
@@ -19,6 +19,8 @@ package org.matrix.android.sdk.internal.session.room
import org.matrix.android.sdk.api.session.crypto.CryptoService
import org.matrix.android.sdk.api.session.room.Room
import org.matrix.android.sdk.internal.session.SessionScope
+import org.matrix.android.sdk.internal.session.permalinks.ViaParameterFinder
+import org.matrix.android.sdk.internal.session.room.accountdata.DefaultRoomAccountDataService
import org.matrix.android.sdk.internal.session.room.alias.DefaultAliasService
import org.matrix.android.sdk.internal.session.room.call.DefaultRoomCallService
import org.matrix.android.sdk.internal.session.room.draft.DefaultDraftService
@@ -59,7 +61,9 @@ internal class DefaultRoomFactory @Inject constructor(private val cryptoService:
private val relationServiceFactory: DefaultRelationService.Factory,
private val membershipServiceFactory: DefaultMembershipService.Factory,
private val roomPushRuleServiceFactory: DefaultRoomPushRuleService.Factory,
+ private val roomAccountDataServiceFactory: DefaultRoomAccountDataService.Factory,
private val sendStateTask: SendStateTask,
+ private val viaParameterFinder: ViaParameterFinder,
private val searchTask: SearchTask) :
RoomFactory {
@@ -82,8 +86,10 @@ internal class DefaultRoomFactory @Inject constructor(private val cryptoService:
relationService = relationServiceFactory.create(roomId),
roomMembersService = membershipServiceFactory.create(roomId),
roomPushRuleService = roomPushRuleServiceFactory.create(roomId),
+ roomAccountDataService = roomAccountDataServiceFactory.create(roomId),
sendStateTask = sendStateTask,
- searchTask = searchTask
+ searchTask = searchTask,
+ viaParameterFinder = viaParameterFinder
)
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt
index 5133f72932..d88c195056 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt
@@ -24,9 +24,12 @@ import org.commonmark.renderer.html.HtmlRenderer
import org.matrix.android.sdk.api.session.file.FileService
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.space.SpaceService
import org.matrix.android.sdk.internal.session.DefaultFileService
import org.matrix.android.sdk.internal.session.SessionScope
import org.matrix.android.sdk.internal.session.directory.DirectoryAPI
+import org.matrix.android.sdk.internal.session.room.accountdata.DefaultUpdateRoomAccountDataTask
+import org.matrix.android.sdk.internal.session.room.accountdata.UpdateRoomAccountDataTask
import org.matrix.android.sdk.internal.session.room.alias.AddRoomAliasTask
import org.matrix.android.sdk.internal.session.room.alias.DefaultAddRoomAliasTask
import org.matrix.android.sdk.internal.session.room.alias.DefaultDeleteRoomAliasTask
@@ -89,6 +92,7 @@ import org.matrix.android.sdk.internal.session.room.typing.DefaultSendTypingTask
import org.matrix.android.sdk.internal.session.room.typing.SendTypingTask
import org.matrix.android.sdk.internal.session.room.uploads.DefaultGetUploadsTask
import org.matrix.android.sdk.internal.session.room.uploads.GetUploadsTask
+import org.matrix.android.sdk.internal.session.space.DefaultSpaceService
import retrofit2.Retrofit
@Module
@@ -135,6 +139,9 @@ internal abstract class RoomModule {
@Binds
abstract fun bindRoomService(service: DefaultRoomService): RoomService
+ @Binds
+ abstract fun bindSpaceService(service: DefaultSpaceService): SpaceService
+
@Binds
abstract fun bindRoomDirectoryService(service: DefaultRoomDirectoryService): RoomDirectoryService
@@ -231,6 +238,9 @@ internal abstract class RoomModule {
@Binds
abstract fun bindPeekRoomTask(task: DefaultPeekRoomTask): PeekRoomTask
+ @Binds
+ abstract fun bindUpdateRoomAccountDataTask(task: DefaultUpdateRoomAccountDataTask): UpdateRoomAccountDataTask
+
@Binds
abstract fun bindGetEventTask(task: DefaultGetEventTask): GetEventTask
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/SpaceGetter.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/SpaceGetter.kt
new file mode 100644
index 0000000000..fed3ff542b
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/SpaceGetter.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2021 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.internal.session.room
+
+import org.matrix.android.sdk.api.session.space.Space
+import javax.inject.Inject
+
+internal interface SpaceGetter {
+ fun get(spaceId: String): Space?
+}
+
+internal class DefaultSpaceGetter @Inject constructor(
+ private val roomGetter: RoomGetter
+) : SpaceGetter {
+
+ override fun get(spaceId: String): Space? {
+ return roomGetter.getRoom(spaceId)?.asSpace()
+ }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/accountdata/DefaultRoomAccountDataService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/accountdata/DefaultRoomAccountDataService.kt
new file mode 100644
index 0000000000..d43c1d3217
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/accountdata/DefaultRoomAccountDataService.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2021 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.internal.session.room.accountdata
+
+import androidx.lifecycle.LiveData
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import org.matrix.android.sdk.api.session.events.model.Content
+import org.matrix.android.sdk.api.session.room.accountdata.RoomAccountDataEvent
+import org.matrix.android.sdk.api.session.room.accountdata.RoomAccountDataService
+import org.matrix.android.sdk.api.util.Optional
+
+internal class DefaultRoomAccountDataService @AssistedInject constructor(@Assisted private val roomId: String,
+ private val dataSource: RoomAccountDataDataSource,
+ private val updateRoomAccountDataTask: UpdateRoomAccountDataTask
+) : RoomAccountDataService {
+
+ @AssistedFactory
+ interface Factory {
+ fun create(roomId: String): DefaultRoomAccountDataService
+ }
+
+ override fun getAccountDataEvent(type: String): RoomAccountDataEvent? {
+ return dataSource.getAccountDataEvent(roomId, type)
+ }
+
+ override fun getLiveAccountDataEvent(type: String): LiveData> {
+ return dataSource.getLiveAccountDataEvent(roomId, type)
+ }
+
+ override fun getAccountDataEvents(types: Set): List {
+ return dataSource.getAccountDataEvents(roomId, types)
+ }
+
+ override fun getLiveAccountDataEvents(types: Set): LiveData> {
+ return dataSource.getLiveAccountDataEvents(roomId, types)
+ }
+
+ override suspend fun updateAccountData(type: String, content: Content) {
+ val params = UpdateRoomAccountDataTask.Params(roomId, type, content)
+ return updateRoomAccountDataTask.execute(params)
+ }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/accountdata/RoomAccountDataDataSource.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/accountdata/RoomAccountDataDataSource.kt
new file mode 100644
index 0000000000..0e4493846c
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/accountdata/RoomAccountDataDataSource.kt
@@ -0,0 +1,98 @@
+/*
+ * 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.session.room.accountdata
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MediatorLiveData
+import androidx.lifecycle.Transformations
+import com.zhuinden.monarchy.Monarchy
+import io.realm.Realm
+import io.realm.RealmQuery
+import org.matrix.android.sdk.api.session.room.accountdata.RoomAccountDataEvent
+import org.matrix.android.sdk.api.util.Optional
+import org.matrix.android.sdk.api.util.toOptional
+import org.matrix.android.sdk.internal.database.RealmSessionProvider
+import org.matrix.android.sdk.internal.database.mapper.AccountDataMapper
+import org.matrix.android.sdk.internal.database.model.RoomAccountDataEntityFields
+import org.matrix.android.sdk.internal.database.model.RoomEntity
+import org.matrix.android.sdk.internal.database.model.RoomEntityFields
+import org.matrix.android.sdk.internal.di.SessionDatabase
+import javax.inject.Inject
+
+internal class RoomAccountDataDataSource @Inject constructor(@SessionDatabase private val monarchy: Monarchy,
+ private val realmSessionProvider: RealmSessionProvider,
+ private val accountDataMapper: AccountDataMapper) {
+
+ fun getAccountDataEvent(roomId: String, type: String): RoomAccountDataEvent? {
+ return getAccountDataEvents(roomId, setOf(type)).firstOrNull()
+ }
+
+ fun getLiveAccountDataEvent(roomId: String, type: String): LiveData> {
+ return Transformations.map(getLiveAccountDataEvents(roomId, setOf(type))) {
+ it.firstOrNull()?.toOptional()
+ }
+ }
+
+ /**
+ * @param roomId the roomId to search for account data event. If null will check in every room.
+ * @param types the types to filter. If empty will return all account data event in given room (or every room if roomId is null)
+ *
+ */
+ fun getAccountDataEvents(roomId: String?, types: Set): List {
+ return realmSessionProvider.withRealm { realm ->
+ val roomEntity = buildRoomQuery(realm, roomId, types).findFirst() ?: return@withRealm emptyList()
+ roomEntity.accountDataEvents(types)
+ }
+ }
+
+ /**
+ * @param roomId the roomId to search for account data event. If null will check in every room.
+ * @param types the types to filter. If empty will return all account data event in the given room (or every room if roomId is null).
+ *
+ */
+ fun getLiveAccountDataEvents(roomId: String?, types: Set): LiveData> {
+ val liveRoomEntity = monarchy.findAllManagedWithChanges {
+ buildRoomQuery(it, roomId, types)
+ }
+ val resultLiveData = MediatorLiveData>()
+ resultLiveData.addSource(liveRoomEntity) { changeSet ->
+ val mappedResult = changeSet.realmResults.flatMap { it.accountDataEvents(types) }
+ resultLiveData.postValue(mappedResult)
+ }
+ return resultLiveData
+ }
+
+ private fun buildRoomQuery(realm: Realm, roomId: String?, types: Set): RealmQuery {
+ val query = realm.where(RoomEntity::class.java)
+ if (roomId != null) {
+ query.equalTo(RoomEntityFields.ROOM_ID, roomId)
+ }
+ query.isNotEmpty(RoomEntityFields.ACCOUNT_DATA.`$`)
+ if (types.isNotEmpty()) {
+ query.`in`(RoomEntityFields.ACCOUNT_DATA.TYPE, types.toTypedArray())
+ }
+ return query
+ }
+
+ private fun RoomEntity.accountDataEvents(types: Set): List {
+ val query = accountData.where()
+ if (types.isNotEmpty()) {
+ query.`in`(RoomAccountDataEntityFields.TYPE, types.toTypedArray())
+ }
+ return query.findAll().map { accountDataMapper.map(roomId, it) }
+ }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/accountdata/UpdateRoomAccountDataTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/accountdata/UpdateRoomAccountDataTask.kt
new file mode 100644
index 0000000000..db18c18908
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/accountdata/UpdateRoomAccountDataTask.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2021 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.internal.session.room.accountdata
+
+import org.matrix.android.sdk.api.util.JsonDict
+import org.matrix.android.sdk.internal.di.UserId
+import org.matrix.android.sdk.internal.network.GlobalErrorReceiver
+import org.matrix.android.sdk.internal.network.executeRequest
+import org.matrix.android.sdk.internal.session.room.RoomAPI
+import org.matrix.android.sdk.internal.task.Task
+import javax.inject.Inject
+
+internal interface UpdateRoomAccountDataTask : Task {
+
+ data class Params(
+ val roomId: String,
+ val type: String,
+ val content: JsonDict
+ )
+}
+
+internal class DefaultUpdateRoomAccountDataTask @Inject constructor(
+ private val roomApi: RoomAPI,
+ @UserId private val userId: String,
+ private val globalErrorReceiver: GlobalErrorReceiver
+) : UpdateRoomAccountDataTask {
+
+ override suspend fun execute(params: UpdateRoomAccountDataTask.Params) {
+ return executeRequest(globalErrorReceiver) {
+ roomApi.setRoomAccountData(userId, params.roomId, params.type, params.content)
+ }
+ }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/RoomAliasAvailabilityChecker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/RoomAliasAvailabilityChecker.kt
index 9faf50dd8b..b39cbaa582 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/RoomAliasAvailabilityChecker.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/RoomAliasAvailabilityChecker.kt
@@ -36,7 +36,11 @@ internal class RoomAliasAvailabilityChecker @Inject constructor(
@Throws(RoomAliasError::class)
suspend fun check(aliasLocalPart: String?) {
if (aliasLocalPart.isNullOrEmpty()) {
- throw RoomAliasError.AliasEmpty
+ // don't check empty or not provided alias
+ return
+ }
+ if (aliasLocalPart.isBlank()) {
+ throw RoomAliasError.AliasIsBlank
}
// Check alias availability
val fullAlias = aliasLocalPart.toFullLocalAlias(userId)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBody.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBody.kt
index 13d403e2e4..69352688e3 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBody.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBody.kt
@@ -111,5 +111,12 @@ internal data class CreateRoomBody(
* The power level content to override in the default power level event
*/
@Json(name = "power_level_content_override")
- val powerLevelContentOverride: PowerLevelsContent?
+ val powerLevelContentOverride: PowerLevelsContent?,
+
+ /**
+ * The room version to set for the room. If not provided, the homeserver is to use its configured default.
+ * If provided, the homeserver will return a 400 error with the errcode M_UNSUPPORTED_ROOM_VERSION if it does not support the room version.
+ */
+ @Json(name = "room_version")
+ val roomVersion: String?
)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBodyBuilder.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBodyBuilder.kt
index 5e823fc87f..018b865388 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBodyBuilder.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBodyBuilder.kt
@@ -20,13 +20,19 @@ import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.session.crypto.crosssigning.CrossSigningService
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.identity.IdentityServiceError
import org.matrix.android.sdk.api.session.identity.toMedium
+import org.matrix.android.sdk.api.session.room.model.GuestAccess
+import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibility
+import org.matrix.android.sdk.api.session.room.model.RoomJoinRules
+import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesContent
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
import org.matrix.android.sdk.api.util.MimeTypes
import org.matrix.android.sdk.internal.crypto.DeviceListManager
import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM
import org.matrix.android.sdk.internal.di.AuthenticatedIdentity
+import org.matrix.android.sdk.internal.di.UserId
import org.matrix.android.sdk.internal.network.token.AccessTokenProvider
import org.matrix.android.sdk.internal.session.content.FileUploader
import org.matrix.android.sdk.internal.session.identity.EnsureIdentityTokenTask
@@ -43,6 +49,8 @@ internal class CreateRoomBodyBuilder @Inject constructor(
private val deviceListManager: DeviceListManager,
private val identityStore: IdentityStore,
private val fileUploader: FileUploader,
+ @UserId
+ private val userId: String,
@AuthenticatedIdentity
private val accessTokenProvider: AccessTokenProvider
) {
@@ -68,10 +76,17 @@ internal class CreateRoomBodyBuilder @Inject constructor(
}
}
+ if (params.joinRuleRestricted != null) {
+ params.roomVersion = "org.matrix.msc3083"
+ params.historyVisibility = params.historyVisibility ?: RoomHistoryVisibility.SHARED
+ params.guestAccess = params.guestAccess ?: GuestAccess.Forbidden
+ }
val initialStates = listOfNotNull(
buildEncryptionWithAlgorithmEvent(params),
buildHistoryVisibilityEvent(params),
- buildAvatarEvent(params)
+ buildAvatarEvent(params),
+ buildGuestAccess(params),
+ buildJoinRulesRestricted(params)
)
.takeIf { it.isNotEmpty() }
@@ -80,13 +95,15 @@ internal class CreateRoomBodyBuilder @Inject constructor(
roomAliasName = params.roomAliasName,
name = params.name,
topic = params.topic,
- invitedUserIds = params.invitedUserIds,
+ invitedUserIds = params.invitedUserIds.filter { it != userId },
invite3pids = invite3pids,
creationContent = params.creationContent.takeIf { it.isNotEmpty() },
initialStates = initialStates,
preset = params.preset,
isDirect = params.isDirect,
- powerLevelContentOverride = params.powerLevelContentOverride
+ powerLevelContentOverride = params.powerLevelContentOverride,
+ roomVersion = params.roomVersion
+
)
}
@@ -120,6 +137,31 @@ internal class CreateRoomBodyBuilder @Inject constructor(
}
}
+ private fun buildGuestAccess(params: CreateRoomParams): Event? {
+ return params.guestAccess
+ ?.let {
+ Event(
+ type = EventType.STATE_ROOM_GUEST_ACCESS,
+ stateKey = "",
+ content = mapOf("guest_access" to it.value)
+ )
+ }
+ }
+
+ private fun buildJoinRulesRestricted(params: CreateRoomParams): Event? {
+ return params.joinRuleRestricted
+ ?.let { allowList ->
+ Event(
+ type = EventType.STATE_ROOM_JOIN_RULES,
+ stateKey = "",
+ content = RoomJoinRulesContent(
+ _joinRules = RoomJoinRules.RESTRICTED.value,
+ allowList = allowList
+ ).toContent()
+ )
+ }
+ }
+
/**
* Add the crypto algorithm to the room creation parameters.
*/
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomTask.kt
index bafe2b90ae..de6a71e581 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomTask.kt
@@ -102,7 +102,7 @@ internal class DefaultCreateRoomTask @Inject constructor(
.equalTo(RoomSummaryEntityFields.MEMBERSHIP_STR, Membership.JOIN.name)
}
} catch (exception: TimeoutCancellationException) {
- throw CreateRoomFailure.CreatedWithTimeout
+ throw CreateRoomFailure.CreatedWithTimeout(roomId)
}
Realm.getInstance(realmConfiguration).executeTransactionAsync {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/RoomCreateEventProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/RoomCreateEventProcessor.kt
index 95572c203c..cc66a0a2d2 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/RoomCreateEventProcessor.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/RoomCreateEventProcessor.kt
@@ -37,6 +37,7 @@ internal class RoomCreateEventProcessor @Inject constructor() : EventInsertLiveP
val predecessorRoomSummary = RoomSummaryEntity.where(realm, predecessorRoomId).findFirst()
?: RoomSummaryEntity(predecessorRoomId)
predecessorRoomSummary.versioningState = VersioningState.UPGRADED_ROOM_JOINED
+ predecessorRoomSummary.isHiddenFromUser = true
realm.insertOrUpdate(predecessorRoomSummary)
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/peeking/PeekRoomTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/peeking/PeekRoomTask.kt
index 5b211c505f..219e9c903f 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/peeking/PeekRoomTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/peeking/PeekRoomTask.kt
@@ -23,11 +23,16 @@ import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.room.model.RoomAvatarContent
import org.matrix.android.sdk.api.session.room.model.RoomCanonicalAliasContent
import org.matrix.android.sdk.api.session.room.model.RoomDirectoryVisibility
+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.RoomNameContent
import org.matrix.android.sdk.api.session.room.model.RoomTopicContent
+import org.matrix.android.sdk.api.session.room.model.create.RoomCreateContent
import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoomsFilter
import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoomsParams
import org.matrix.android.sdk.api.session.room.peeking.PeekResult
+import org.matrix.android.sdk.api.util.MatrixItem
import org.matrix.android.sdk.internal.session.room.alias.GetRoomIdByAliasTask
import org.matrix.android.sdk.internal.session.room.directory.GetPublicRoomTask
import org.matrix.android.sdk.internal.session.room.directory.GetRoomDirectoryVisibilityTask
@@ -100,7 +105,10 @@ internal class DefaultPeekRoomTask @Inject constructor(
name = publicRepoResult.name,
topic = publicRepoResult.topic,
numJoinedMembers = publicRepoResult.numJoinedMembers,
- viaServers = serverList
+ viaServers = serverList,
+ roomType = null, // would be nice to get that from directory...
+ someMembers = null,
+ isPublic = true
)
}
@@ -125,11 +133,30 @@ internal class DefaultPeekRoomTask @Inject constructor(
?.let { it.content?.toModel()?.canonicalAlias }
// not sure if it's the right way to do that :/
- val memberCount = stateEvents
+ val membersEvent = stateEvents
.filter { it.type == EventType.STATE_ROOM_MEMBER && it.stateKey?.isNotEmpty() == true }
+
+ val memberCount = membersEvent
.distinctBy { it.stateKey }
.count()
+ val someMembers = membersEvent.mapNotNull { ev ->
+ ev.content?.toModel()?.let {
+ MatrixItem.UserItem(ev.stateKey ?: "", it.displayName, it.avatarUrl)
+ }
+ }
+
+ val historyVisibility =
+ stateEvents
+ .lastOrNull { it.type == EventType.STATE_ROOM_HISTORY_VISIBILITY && it.stateKey?.isNotEmpty() == true }
+ ?.let { it.content?.toModel()?.historyVisibility }
+
+ val roomType = stateEvents
+ .lastOrNull { it.type == EventType.STATE_ROOM_CREATE }
+ ?.content
+ ?.toModel()
+ ?.type
+
return PeekResult.Success(
roomId = roomId,
alias = alias,
@@ -137,7 +164,10 @@ internal class DefaultPeekRoomTask @Inject constructor(
name = name,
topic = topic,
numJoinedMembers = memberCount,
- viaServers = serverList
+ roomType = roomType,
+ viaServers = serverList,
+ someMembers = someMembers,
+ isPublic = historyVisibility == RoomHistoryVisibility.WORLD_READABLE
)
} catch (failure: Throwable) {
// Would be M_FORBIDDEN if cannot peek :/
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/EventEditor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/EventEditor.kt
index 5fe06287d2..a666d40fc3 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/EventEditor.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/EventEditor.kt
@@ -99,6 +99,7 @@ internal class EventEditor @Inject constructor(private val eventSenderProcessor:
entity.age = editedEventEntity.age
entity.originServerTs = editedEventEntity.originServerTs
entity.sendState = editedEventEntity.sendState
+ entity.sendStateDetails = editedEventEntity.sendStateDetails
}
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relationship/RoomChildRelationInfo.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relationship/RoomChildRelationInfo.kt
new file mode 100644
index 0000000000..2efea7f118
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relationship/RoomChildRelationInfo.kt
@@ -0,0 +1,104 @@
+/*
+ * 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.session.room.relationship
+
+import io.realm.Realm
+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.space.model.SpaceChildContent
+import org.matrix.android.sdk.api.session.space.model.SpaceParentContent
+import org.matrix.android.sdk.internal.database.mapper.ContentMapper
+import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntity
+import org.matrix.android.sdk.internal.database.query.whereType
+
+/**
+ * Relationship between rooms and spaces
+ * The intention is that rooms and spaces form a hierarchy, which clients can use to structure the user's room list into a tree view.
+ * The parent/child relationship can be expressed in one of two ways:
+ * - The admins of a space can advertise rooms and subspaces for their space by setting m.space.child state events.
+ * The state_key is the ID of a child room or space, and the content should contain a via key which gives
+ * a list of candidate servers that can be used to join the room. present: true key is included to distinguish from a deleted state event.
+ *
+ * - Separately, rooms can claim parents via the m.room.parent state event.
+ */
+internal class RoomChildRelationInfo(
+ private val realm: Realm,
+ private val roomId: String
+) {
+
+ data class SpaceChildInfo(
+ val roomId: String,
+ val order: String?,
+ val autoJoin: Boolean,
+ val viaServers: List
+ )
+
+ data class SpaceParentInfo(
+ val roomId: String,
+ val canonical: Boolean,
+ val viaServers: List,
+ val stateEventSender: String
+ )
+
+ /**
+ * Gets the ordered list of valid child description.
+ */
+ fun getDirectChildrenDescriptions(): List {
+ return CurrentStateEventEntity.whereType(realm, roomId, EventType.STATE_SPACE_CHILD)
+ .findAll()
+// .also {
+// Timber.v("## Space: Found ${it.count()} m.space.child state events for $roomId")
+// }
+ .mapNotNull {
+ ContentMapper.map(it.root?.content).toModel()?.let { scc ->
+// Timber.v("## Space child desc state event $scc")
+ // Children where via is not present are ignored.
+ scc.via?.let { via ->
+ SpaceChildInfo(
+ roomId = it.stateKey,
+ order = scc.validOrder(),
+ autoJoin = scc.autoJoin ?: false,
+ viaServers = via
+ )
+ }
+ }
+ }
+ .sortedBy { it.order }
+ }
+
+ fun getParentDescriptions(): List {
+ return CurrentStateEventEntity.whereType(realm, roomId, EventType.STATE_SPACE_PARENT)
+ .findAll()
+// .also {
+// Timber.v("## Space: Found ${it.count()} m.space.parent state events for $roomId")
+// }
+ .mapNotNull {
+ ContentMapper.map(it.root?.content).toModel()?.let { scc ->
+// Timber.v("## Space parent desc state event $scc")
+ // Parent where via is not present are ignored.
+ scc.via?.let { via ->
+ SpaceParentInfo(
+ roomId = it.stateKey,
+ canonical = scc.canonical ?: false,
+ viaServers = via,
+ stateEventSender = it.root?.sender ?: ""
+ )
+ }
+ }
+ }
+ }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/DefaultSendService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/DefaultSendService.kt
index 26a87557ff..449189e6b5 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/DefaultSendService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/DefaultSendService.kt
@@ -109,14 +109,6 @@ internal class DefaultSendService @AssistedInject constructor(
.let { sendEvent(it) }
}
- override fun sendMedias(attachments: List,
- compressBeforeSending: Boolean,
- roomIds: Set): Cancelable {
- return attachments.mapTo(CancelableBag()) {
- sendMedia(it, compressBeforeSending, roomIds)
- }
- }
-
override fun redactEvent(event: Event, reason: String?): Cancelable {
// TODO manage media/attachements?
val redactionEcho = localEchoEventFactory.createRedactEvent(roomId, event.eventId!!, reason)
@@ -149,7 +141,7 @@ internal class DefaultSendService @AssistedInject constructor(
is MessageImageContent -> {
// The image has not yet been sent
val attachmentData = ContentAttachmentData(
- size = messageContent.info!!.size.toLong(),
+ size = messageContent.info!!.size,
mimeType = messageContent.info.mimeType!!,
width = messageContent.info.width.toLong(),
height = messageContent.info.height.toLong(),
@@ -240,6 +232,14 @@ internal class DefaultSendService @AssistedInject constructor(
}
}
+ override fun sendMedias(attachments: List,
+ compressBeforeSending: Boolean,
+ roomIds: Set): Cancelable {
+ return attachments.mapTo(CancelableBag()) {
+ sendMedia(it, compressBeforeSending, roomIds)
+ }
+ }
+
override fun sendMedia(attachment: ContentAttachmentData,
compressBeforeSending: Boolean,
roomIds: Set): Cancelable {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoEventFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoEventFactory.kt
index 432a4af062..f505b13b33 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoEventFactory.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoEventFactory.kt
@@ -73,6 +73,7 @@ internal class LocalEchoEventFactory @Inject constructor(
@UserId private val userId: String,
private val markdownParser: MarkdownParser,
private val textPillsUtils: TextPillsUtils,
+ private val thumbnailExtractor: ThumbnailExtractor,
private val localEchoRepository: LocalEchoRepository,
private val permalinkFactory: PermalinkFactory
) {
@@ -244,7 +245,7 @@ internal class LocalEchoEventFactory @Inject constructor(
mimeType = attachment.getSafeMimeType(),
width = width?.toInt() ?: 0,
height = height?.toInt() ?: 0,
- size = attachment.size.toInt()
+ size = attachment.size
),
url = attachment.queryUri.toString()
)
@@ -261,7 +262,7 @@ internal class LocalEchoEventFactory @Inject constructor(
val width = firstFrame?.width ?: 0
mediaDataRetriever.release()
- val thumbnailInfo = ThumbnailExtractor.extractThumbnail(context, attachment)?.let {
+ val thumbnailInfo = thumbnailExtractor.extractThumbnail(attachment)?.let {
ThumbnailInfo(
width = it.width,
height = it.height,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoRepository.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoRepository.kt
index 70245cbd5e..e98e5646af 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoRepository.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoRepository.kt
@@ -87,7 +87,7 @@ internal class LocalEchoRepository @Inject constructor(@SessionDatabase private
}
}
- fun updateSendState(eventId: String, roomId: String?, sendState: SendState) {
+ fun updateSendState(eventId: String, roomId: String?, sendState: SendState, sendStateDetails: String? = null) {
Timber.v("## SendEvent: [${System.currentTimeMillis()}] Update local state of $eventId to ${sendState.name}")
timelineInput.onLocalEchoUpdated(roomId = roomId ?: "", eventId = eventId, sendState = sendState)
updateEchoAsync(eventId) { realm, sendingEventEntity ->
@@ -96,6 +96,7 @@ internal class LocalEchoRepository @Inject constructor(@SessionDatabase private
} else {
sendingEventEntity.sendState = sendState
}
+ sendingEventEntity.sendStateDetails = sendStateDetails
roomSummaryUpdater.updateSendingInformation(realm, sendingEventEntity.roomId)
}
}
@@ -161,6 +162,7 @@ internal class LocalEchoRepository @Inject constructor(@SessionDatabase private
val timelineEvents = TimelineEventEntity.where(realm, roomId, eventIds).findAll()
timelineEvents.forEach {
it.root?.sendState = sendState
+ it.root?.sendStateDetails = null
}
roomSummaryUpdater.updateSendingInformation(realm, roomId)
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/MultipleEventSendingDispatcherWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/MultipleEventSendingDispatcherWorker.kt
index bc307bc74f..e889f1a61b 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/MultipleEventSendingDispatcherWorker.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/MultipleEventSendingDispatcherWorker.kt
@@ -55,7 +55,12 @@ internal class MultipleEventSendingDispatcherWorker(context: Context, params: Wo
override fun doOnError(params: Params): Result {
params.localEchoIds.forEach { localEchoIds ->
- localEchoRepository.updateSendState(localEchoIds.eventId, localEchoIds.roomId, SendState.UNDELIVERED)
+ localEchoRepository.updateSendState(
+ eventId = localEchoIds.eventId,
+ roomId = localEchoIds.roomId,
+ sendState = SendState.UNDELIVERED,
+ sendStateDetails = params.lastFailureMessage
+ )
}
return super.doOnError(params)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/SendEventWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/SendEventWorker.kt
index d55dce57af..cd7911910d 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/SendEventWorker.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/SendEventWorker.kt
@@ -26,6 +26,7 @@ import org.matrix.android.sdk.api.session.room.send.SendState
import org.matrix.android.sdk.internal.crypto.tasks.SendEventTask
import org.matrix.android.sdk.internal.di.SessionDatabase
import org.matrix.android.sdk.internal.session.SessionComponent
+import org.matrix.android.sdk.internal.util.toMatrixErrorStr
import org.matrix.android.sdk.internal.worker.SessionSafeCoroutineWorker
import org.matrix.android.sdk.internal.worker.SessionWorkerParams
import timber.log.Timber
@@ -77,7 +78,12 @@ internal class SendEventWorker(context: Context,
}
if (params.lastFailureMessage != null) {
- localEchoRepository.updateSendState(event.eventId, event.roomId, SendState.UNDELIVERED)
+ localEchoRepository.updateSendState(
+ eventId = event.eventId,
+ roomId = event.roomId,
+ sendState = SendState.UNDELIVERED,
+ sendStateDetails = params.lastFailureMessage
+ )
// Transmit the error
return Result.success(inputData)
.also { Timber.e("Work cancelled due to input error from parent") }
@@ -90,7 +96,12 @@ internal class SendEventWorker(context: Context,
} catch (exception: Throwable) {
if (/*currentAttemptCount >= MAX_NUMBER_OF_RETRY_BEFORE_FAILING ||**/ !exception.shouldBeRetried()) {
Timber.e("## SendEvent: [${System.currentTimeMillis()}] Send event Failed cannot retry ${params.eventId} > ${exception.localizedMessage}")
- localEchoRepository.updateSendState(event.eventId, event.roomId, SendState.UNDELIVERED)
+ localEchoRepository.updateSendState(
+ eventId = event.eventId,
+ roomId = event.roomId,
+ sendState = SendState.UNDELIVERED,
+ sendStateDetails = exception.toMatrixErrorStr()
+ )
Result.success()
} else {
Timber.e("## SendEvent: [${System.currentTimeMillis()}] Send event Failed schedule retry ${params.eventId} > ${exception.localizedMessage}")
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessor.kt
index 8bafa5f882..cd5bf575db 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessor.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessor.kt
@@ -18,7 +18,7 @@ package org.matrix.android.sdk.internal.session.room.send.queue
import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.util.Cancelable
-import org.matrix.android.sdk.internal.session.SessionLifecycleObserver
+import org.matrix.android.sdk.api.session.SessionLifecycleObserver
internal interface EventSenderProcessor: SessionLifecycleObserver {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessorCoroutine.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessorCoroutine.kt
index a5c09f5ff6..80bfd02b0e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessorCoroutine.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessorCoroutine.kt
@@ -25,6 +25,7 @@ import org.matrix.android.sdk.api.auth.data.SessionParams
import org.matrix.android.sdk.api.failure.Failure
import org.matrix.android.sdk.api.failure.MatrixError
import org.matrix.android.sdk.api.failure.getRetryDelay
+import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.crypto.CryptoService
import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.util.Cancelable
@@ -72,7 +73,7 @@ internal class EventSenderProcessorCoroutine @Inject constructor(
*/
private val cancelableBag = ConcurrentHashMap()
- override fun onSessionStarted() {
+ override fun onSessionStarted(session: Session) {
// We should check for sending events not handled because app was killed
// But we should be careful of only took those that was submitted to us, because if it's
// for example it's a media event it is handled by some worker and he will handle it
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessorThread.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessorThread.kt
index b79a86dd7e..9db7cc9039 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessorThread.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessorThread.kt
@@ -25,6 +25,7 @@ import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.failure.Failure
import org.matrix.android.sdk.api.failure.MatrixError
import org.matrix.android.sdk.api.failure.isTokenError
+import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.crypto.CryptoService
import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.sync.SyncState
@@ -64,11 +65,11 @@ internal class EventSenderProcessorThread @Inject constructor(
memento.unTrack(task)
}
- override fun onSessionStarted() {
+ override fun onSessionStarted(session: Session) {
start()
}
- override fun onSessionStopped() {
+ override fun onSessionStopped(session: Session) {
interrupt()
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/DefaultStateService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/DefaultStateService.kt
index 615bc99096..ff2afb5d61 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/DefaultStateService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/DefaultStateService.kt
@@ -34,6 +34,7 @@ import org.matrix.android.sdk.api.util.JsonDict
import org.matrix.android.sdk.api.util.MimeTypes
import org.matrix.android.sdk.api.util.Optional
import org.matrix.android.sdk.internal.session.content.FileUploader
+import java.lang.UnsupportedOperationException
internal class DefaultStateService @AssistedInject constructor(@Assisted private val roomId: String,
private val stateEventDataSource: StateEventDataSource,
@@ -73,7 +74,7 @@ internal class DefaultStateService @AssistedInject constructor(@Assisted private
eventType = eventType,
body = body.toSafeJson(eventType)
)
- sendStateTask.execute(params)
+ sendStateTask.executeRetry(params, 3)
}
private fun JsonDict.toSafeJson(eventType: String): JsonDict {
@@ -127,6 +128,7 @@ internal class DefaultStateService @AssistedInject constructor(@Assisted private
override suspend fun updateJoinRule(joinRules: RoomJoinRules?, guestAccess: GuestAccess?) {
if (joinRules != null) {
+ if (joinRules == RoomJoinRules.RESTRICTED) throw UnsupportedOperationException("No yet supported")
sendStateEvent(
eventType = EventType.STATE_ROOM_JOIN_RULES,
body = mapOf("join_rule" to joinRules),
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/SafePowerLevelContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/SafePowerLevelContent.kt
index a97709e38b..197b4f8688 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/SafePowerLevelContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/SafePowerLevelContent.kt
@@ -21,22 +21,21 @@ import com.squareup.moshi.JsonClass
import org.matrix.android.sdk.api.session.events.model.toContent
import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
-import org.matrix.android.sdk.api.session.room.powerlevels.Role
import org.matrix.android.sdk.api.util.JsonDict
@JsonClass(generateAdapter = true)
internal data class SerializablePowerLevelsContent(
- @Json(name = "ban") val ban: Int = Role.Moderator.value,
- @Json(name = "kick") val kick: Int = Role.Moderator.value,
- @Json(name = "invite") val invite: Int = Role.Moderator.value,
- @Json(name = "redact") val redact: Int = Role.Moderator.value,
- @Json(name = "events_default") val eventsDefault: Int = Role.Default.value,
- @Json(name = "events") val events: Map = emptyMap(),
- @Json(name = "users_default") val usersDefault: Int = Role.Default.value,
- @Json(name = "users") val users: Map = emptyMap(),
- @Json(name = "state_default") val stateDefault: Int = Role.Moderator.value,
+ @Json(name = "ban") val ban: Int?,
+ @Json(name = "kick") val kick: Int?,
+ @Json(name = "invite") val invite: Int?,
+ @Json(name = "redact") val redact: Int?,
+ @Json(name = "events_default") val eventsDefault: Int?,
+ @Json(name = "events") val events: Map?,
+ @Json(name = "users_default") val usersDefault: Int?,
+ @Json(name = "users") val users: Map?,
+ @Json(name = "state_default") val stateDefault: Int?,
// `Int` is the diff here (instead of `Any`)
- @Json(name = "notifications") val notifications: Map = emptyMap()
+ @Json(name = "notifications") val notifications: Map?
)
internal fun JsonDict.toSafePowerLevelsContentDict(): JsonDict {
@@ -52,7 +51,7 @@ internal fun JsonDict.toSafePowerLevelsContentDict(): JsonDict {
usersDefault = content.usersDefault,
users = content.users,
stateDefault = content.stateDefault,
- notifications = content.notifications.mapValues { content.notificationLevel(it.key) }
+ notifications = content.notifications?.mapValues { content.notificationLevel(it.key) }
)
}
?.toContent()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/GraphUtils.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/GraphUtils.kt
new file mode 100644
index 0000000000..b7e6548b54
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/GraphUtils.kt
@@ -0,0 +1,166 @@
+/*
+ * 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.internal.session.room.summary
+
+import java.util.LinkedList
+
+data class GraphNode(
+ val name: String
+)
+
+data class GraphEdge(
+ val source: GraphNode,
+ val destination: GraphNode
+)
+
+class Graph {
+
+ private val adjacencyList: HashMap> = HashMap()
+
+ fun getOrCreateNode(name: String): GraphNode {
+ return adjacencyList.entries.firstOrNull { it.key.name == name }?.key
+ ?: GraphNode(name).also {
+ adjacencyList[it] = ArrayList()
+ }
+ }
+
+ fun addEdge(sourceName: String, destinationName: String) {
+ val source = getOrCreateNode(sourceName)
+ val destination = getOrCreateNode(destinationName)
+ adjacencyList.getOrPut(source) { ArrayList() }.add(
+ GraphEdge(source, destination)
+ )
+ }
+
+ fun addEdge(source: GraphNode, destination: GraphNode) {
+ adjacencyList.getOrPut(source) { ArrayList() }.add(
+ GraphEdge(source, destination)
+ )
+ }
+
+ fun edgesOf(node: GraphNode): List {
+ return adjacencyList[node]?.toList() ?: emptyList()
+ }
+
+ fun withoutEdges(edgesToPrune: List): Graph {
+ val output = Graph()
+ this.adjacencyList.forEach { (vertex, edges) ->
+ output.getOrCreateNode(vertex.name)
+ edges.forEach {
+ if (!edgesToPrune.contains(it)) {
+ // add it
+ output.addEdge(it.source, it.destination)
+ }
+ }
+ }
+ return output
+ }
+
+ /**
+ * Depending on the chosen starting point the background edge might change
+ */
+ fun findBackwardEdges(startFrom: GraphNode? = null): List {
+ val backwardEdges = mutableSetOf()
+ val visited = mutableMapOf()
+ val notVisited = -1
+ val inPath = 0
+ val completed = 1
+ adjacencyList.keys.forEach {
+ visited[it] = notVisited
+ }
+ val stack = LinkedList()
+
+ (startFrom ?: adjacencyList.entries.firstOrNull { visited[it.key] == notVisited }?.key)
+ ?.let {
+ stack.push(it)
+ visited[it] = inPath
+ }
+
+ while (stack.isNotEmpty()) {
+// Timber.w("VAL: current stack: ${stack.reversed().joinToString { it.name }}")
+ val vertex = stack.peek() ?: break
+ // peek a path to follow
+ var destination: GraphNode? = null
+ edgesOf(vertex).forEach {
+ when (visited[it.destination]) {
+ notVisited -> {
+ // it's a candidate
+ destination = it.destination
+ }
+ inPath -> {
+ // Cycle!!
+ backwardEdges.add(it)
+ }
+ completed -> {
+ // dead end
+ }
+ }
+ }
+ if (destination == null) {
+ // dead end, pop
+ stack.pop().let {
+ visited[it] = completed
+ }
+ } else {
+ // go down this path
+ stack.push(destination)
+ visited[destination!!] = inPath
+ }
+
+ if (stack.isEmpty()) {
+ // try to get another graph of forest?
+ adjacencyList.entries.firstOrNull { visited[it.key] == notVisited }?.key?.let {
+ stack.push(it)
+ visited[it] = inPath
+ }
+ }
+ }
+
+ return backwardEdges.toList()
+ }
+
+ /**
+ * Only call that on acyclic graph!
+ */
+ fun flattenDestination(): Map> {
+ val result = HashMap>()
+ adjacencyList.keys.forEach { vertex ->
+ result[vertex] = flattenOf(vertex)
+ }
+ return result
+ }
+
+ private fun flattenOf(node: GraphNode): Set {
+ val result = mutableSetOf()
+ val edgesOf = edgesOf(node)
+ result.addAll(edgesOf.map { it.destination })
+ edgesOf.forEach {
+ result.addAll(flattenOf(it.destination))
+ }
+ return result
+ }
+
+ override fun toString(): String {
+ return buildString {
+ adjacencyList.forEach { (node, edges) ->
+ append("${node.name} : [")
+ append(edges.joinToString(" ") { it.destination.name })
+ append("]\n")
+ }
+ }
+ }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/HierarchyLiveDataHelper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/HierarchyLiveDataHelper.kt
new file mode 100644
index 0000000000..29db8431fd
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/HierarchyLiveDataHelper.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2021 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.matrix.android.sdk.internal.session.room.summary
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MediatorLiveData
+import org.matrix.android.sdk.api.session.room.model.Membership
+import org.matrix.android.sdk.api.session.room.model.RoomSummary
+import org.matrix.android.sdk.api.util.Optional
+
+internal class HierarchyLiveDataHelper(
+ val spaceId: String,
+ val memberships: List,
+ val roomSummaryDataSource: RoomSummaryDataSource) {
+
+ private val sources = HashMap>>()
+ private val mediatorLiveData = MediatorLiveData>()
+
+ fun liveData(): LiveData> = mediatorLiveData
+
+ init {
+ onChange()
+ }
+
+ private fun parentsToCheck(): List {
+ val spaces = ArrayList()
+ roomSummaryDataSource.getSpaceSummary(spaceId)?.let {
+ roomSummaryDataSource.flattenSubSpace(it, emptyList(), spaces, memberships)
+ }
+ return spaces
+ }
+
+ private fun onChange() {
+ val existingSources = sources.keys.toList()
+ val newSources = parentsToCheck().map { it.roomId }
+ val addedSources = newSources.filter { !existingSources.contains(it) }
+ val removedSource = existingSources.filter { !newSources.contains(it) }
+ addedSources.forEach {
+ val liveData = roomSummaryDataSource.getSpaceSummaryLive(it)
+ mediatorLiveData.addSource(liveData) { onChange() }
+ sources[it] = liveData
+ }
+
+ removedSource.forEach {
+ sources[it]?.let { mediatorLiveData.removeSource(it) }
+ }
+
+ sources[spaceId]?.value?.getOrNull()?.let { spaceSummary ->
+ val results = ArrayList()
+ roomSummaryDataSource.flattenChild(spaceSummary, emptyList(), results, memberships)
+ mediatorLiveData.postValue(results.map { it.roomId })
+ }
+ }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryDataSource.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryDataSource.kt
index dd3fbe04b2..bff1af60ca 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryDataSource.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryDataSource.kt
@@ -1,5 +1,6 @@
/*
* Copyright 2020 The Matrix.org Foundation C.I.C.
+ * Copyright 2021 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,6 +18,7 @@
package org.matrix.android.sdk.internal.session.room.summary
import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Transformations
import androidx.paging.LivePagedListBuilder
import androidx.paging.PagedList
@@ -24,12 +26,20 @@ import com.zhuinden.monarchy.Monarchy
import io.realm.Realm
import io.realm.RealmQuery
import io.realm.Sort
+import io.realm.kotlin.where
+import org.matrix.android.sdk.api.query.ActiveSpaceFilter
import org.matrix.android.sdk.api.query.RoomCategoryFilter
+import org.matrix.android.sdk.api.session.room.ResultBoundaries
+import org.matrix.android.sdk.api.session.room.RoomSortOrder
import org.matrix.android.sdk.api.session.room.RoomSummaryQueryParams
-import org.matrix.android.sdk.api.session.room.UpdatableFilterLivePageResult
+import org.matrix.android.sdk.api.session.room.UpdatableLivePageResult
+import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.model.RoomSummary
-import org.matrix.android.sdk.api.session.room.model.VersioningState
+import org.matrix.android.sdk.api.session.room.model.RoomType
+import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
+import org.matrix.android.sdk.api.session.room.spaceSummaryQueryParams
import org.matrix.android.sdk.api.session.room.summary.RoomAggregateNotificationCount
+import org.matrix.android.sdk.api.session.space.SpaceSummaryQueryParams
import org.matrix.android.sdk.api.util.Optional
import org.matrix.android.sdk.api.util.toOptional
import org.matrix.android.sdk.internal.database.mapper.RoomSummaryMapper
@@ -79,11 +89,60 @@ internal class RoomSummaryDataSource @Inject constructor(@SessionDatabase privat
fun getRoomSummariesLive(queryParams: RoomSummaryQueryParams): LiveData> {
return monarchy.findAllMappedWithChanges(
- { roomSummariesQuery(it, queryParams) },
+ {
+ roomSummariesQuery(it, queryParams)
+ .sort(RoomSummaryEntityFields.LAST_ACTIVITY_TIME, Sort.DESCENDING)
+ },
{ roomSummaryMapper.map(it) }
)
}
+ fun getSpaceSummariesLive(queryParams: SpaceSummaryQueryParams): LiveData> {
+ return getRoomSummariesLive(queryParams)
+ }
+
+ fun getSpaceSummary(roomIdOrAlias: String): RoomSummary? {
+ return getRoomSummary(roomIdOrAlias)
+ ?.takeIf { it.roomType == RoomType.SPACE }
+ }
+
+ fun getSpaceSummaryLive(roomId: String): LiveData> {
+ val liveData = monarchy.findAllMappedWithChanges(
+ { realm ->
+ RoomSummaryEntity.where(realm, roomId)
+ .isNotEmpty(RoomSummaryEntityFields.DISPLAY_NAME)
+ .equalTo(RoomSummaryEntityFields.ROOM_TYPE, RoomType.SPACE)
+ },
+ {
+ roomSummaryMapper.map(it)
+ }
+ )
+ return Transformations.map(liveData) { results ->
+ results.firstOrNull().toOptional()
+ }
+ }
+
+ fun getSpaceSummaries(spaceSummaryQueryParams: SpaceSummaryQueryParams): List {
+ return getRoomSummaries(spaceSummaryQueryParams)
+ }
+
+ fun getRootSpaceSummaries(): List {
+ return getRoomSummaries(spaceSummaryQueryParams {
+ memberships = listOf(Membership.JOIN)
+ })
+ .let { allJoinedSpace ->
+ val allFlattenChildren = arrayListOf()
+ allJoinedSpace.forEach {
+ flattenSubSpace(it, emptyList(), allFlattenChildren, listOf(Membership.JOIN), false)
+ }
+ val knownNonOrphan = allFlattenChildren.map { it.roomId }.distinct()
+ // keep only root rooms
+ allJoinedSpace.filter { candidate ->
+ !knownNonOrphan.contains(candidate.roomId)
+ }
+ }
+ }
+
fun getBreadcrumbs(queryParams: RoomSummaryQueryParams): List