Merge branch 'develop' into feature/fga/timeline_chunks_rework
This commit is contained in:
commit
63aa5b4015
21
.github/ISSUE_TEMPLATE/release.yml
vendored
21
.github/ISSUE_TEMPLATE/release.yml
vendored
@ -36,6 +36,7 @@ body:
|
||||
- [ ] Push `main` and the new tag `v1.1.10` to origin
|
||||
- [ ] Checkout `develop`
|
||||
- [ ] Increase version in `./vector/build.gradle`
|
||||
- [ ] Change the value of SDK_VERSION in the file `./matrix-sdk-android/build.gradle`
|
||||
- [ ] Commit and push `develop`
|
||||
- [ ] Wait for [Buildkite](https://buildkite.com/matrix-dot-org/element-android/builds?branch=main) to build the `main` branch.
|
||||
- [ ] Run the script `~/scripts/releaseElement.sh`. It will download the APKs from Buildkite check them and sign them.
|
||||
@ -72,9 +73,25 @@ body:
|
||||
- [ ] Create a release with GitFlow
|
||||
- [ ] Update the files `./build.gradle` and `./gradle/gradle-wrapper.properties` manually, to use the latest version for the dependency. You can get inspired by the same files on Element Android project.
|
||||
- [ ] Run the script `./tools/import_from_element.sh`
|
||||
- [ ] Update the version in `./matrix-sdk-android/build.gradle` and let the script finish to build the library
|
||||
- [ ] Update the version in `./matrix-sdk-android/build.gradle`
|
||||
- [ ] Check the diff on this file and restore what may have been erased (in particular the line `apply plugin: "com.vanniktech.maven.publish"`)
|
||||
- [ ] Let the script finish to build the library
|
||||
- [ ] Update the file `CHANGES.md`
|
||||
- [ ] Update the value of VERSION_NAME in the file gradle.properties
|
||||
- [ ] Finish the release using GitFlow
|
||||
|
||||
##### Release on MavenCentral
|
||||
|
||||
- [ ] Run the command `./gradlew publish --no-daemon --no-parallel`. You'll need some non-public element to do so
|
||||
- [ ] Connect to https://s01.oss.sonatype.org
|
||||
- [ ] Click on Staging Repositories and check the the files have been uploaded
|
||||
- [ ] Click on close
|
||||
- [ ] Wait (check Activity tab until step "Repository closed" is displayed)
|
||||
- [ ] Click on release. The staging repository will disappear
|
||||
- [ ] Check that the release is available in https://repo1.maven.org/maven2/org/matrix/android/matrix-android-sdk2/ (it can take a few minutes)
|
||||
|
||||
##### Release on GitHub
|
||||
|
||||
- [ ] Create the release on GitHub from [the tag](https://github.com/matrix-org/matrix-android-sdk2/tags)
|
||||
- [ ] Upload the AAR on the GitHub release
|
||||
|
||||
@ -82,7 +99,7 @@ body:
|
||||
|
||||
https://github.com/matrix-org/matrix-android-sdk2-sample
|
||||
|
||||
- [ ] Update the dependency to the new version of the SDK2. Jitpack will have to build the AAR, it can take a few minutes. You can check status on https://jitpack.io/#matrix-org/matrix-android-sdk2
|
||||
- [ ] Update the dependency to the new version of the SDK2. It can take some time for MavenCentral to make the librarie available. You can check status on https://repo1.maven.org/maven2/org/matrix/android/matrix-android-sdk2/
|
||||
- [ ] Build and run the sample, you may have to fix some API break
|
||||
- [ ] Commit and push directly on `main`
|
||||
validations:
|
||||
|
10
.github/workflows/build.yml
vendored
10
.github/workflows/build.yml
vendored
@ -5,6 +5,12 @@ on:
|
||||
push:
|
||||
branches: [ main, develop ]
|
||||
|
||||
# Enrich gradle.properties for CI/CD
|
||||
env:
|
||||
CI_GRADLE_ARG_PROPERTIES: >
|
||||
-Porg.gradle.jvmargs=-Xmx2g
|
||||
-Porg.gradle.parallel=false
|
||||
|
||||
jobs:
|
||||
debug:
|
||||
name: Build debug APKs (${{ matrix.target }})
|
||||
@ -25,7 +31,7 @@ jobs:
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gradle-
|
||||
- name: Assemble ${{ matrix.target }} debug apk
|
||||
run: ./gradlew assemble${{ matrix.target }}Debug --stacktrace
|
||||
run: ./gradlew assemble${{ matrix.target }}Debug $CI_GRADLE_ARG_PROPERTIES --stacktrace
|
||||
- name: Upload ${{ matrix.target }} debug APKs
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
@ -48,7 +54,7 @@ jobs:
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gradle-
|
||||
- name: Assemble GPlay unsigned apk
|
||||
run: ./gradlew clean assembleGplayRelease --stacktrace
|
||||
run: ./gradlew clean assembleGplayRelease $CI_GRADLE_ARG_PROPERTIES --stacktrace
|
||||
- name: Upload Gplay unsigned APKs
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
|
24
.github/workflows/integration.yml
vendored
24
.github/workflows/integration.yml
vendored
@ -5,6 +5,12 @@ on:
|
||||
push:
|
||||
branches: [ main, develop ]
|
||||
|
||||
# Enrich gradle.properties for CI/CD
|
||||
env:
|
||||
CI_GRADLE_ARG_PROPERTIES: >
|
||||
-Porg.gradle.jvmargs=-Xmx2g
|
||||
-Porg.gradle.parallel=false
|
||||
|
||||
jobs:
|
||||
# Temporary add build of Android tests, which cannot be run on the CI right now, but they need to at least compile
|
||||
# So it will be mandatory for this action to be successful on every PRs
|
||||
@ -22,7 +28,7 @@ jobs:
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gradle-
|
||||
- name: Compile Android tests
|
||||
run: ./gradlew clean assembleAndroidTest --stacktrace -PallWarningsAsErrors=false
|
||||
run: ./gradlew clean assembleAndroidTest $CI_GRADLE_ARG_PROPERTIES --stacktrace -PallWarningsAsErrors=false
|
||||
|
||||
integration-tests:
|
||||
name: Integration Tests (Synapse)
|
||||
@ -30,9 +36,14 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
api-level: [21, 28, 30]
|
||||
api-level: [28]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: gradle/wrapper-validation-action@v1
|
||||
- uses: actions/setup-java@v2
|
||||
with:
|
||||
distribution: 'adopt'
|
||||
java-version: 11
|
||||
- name: Set up Python 3.8
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
@ -64,5 +75,12 @@ jobs:
|
||||
uses: reactivecircus/android-emulator-runner@v2
|
||||
with:
|
||||
api-level: ${{ matrix.api-level }}
|
||||
#arch: x86_64
|
||||
#disable-animations: true
|
||||
# script: ./gradlew -PallWarningsAsErrors=false vector:connectedAndroidTest matrix-sdk-android:connectedAndroidTest
|
||||
script: ./gradlew -PallWarningsAsErrors=false connectedCheck
|
||||
arch: x86
|
||||
profile: Nexus 5X
|
||||
force-avd-creation: false
|
||||
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
|
||||
emulator-build: 7425822
|
||||
script: ./gradlew $CI_GRADLE_ARG_PROPERTIES -PallWarningsAsErrors=false connectedCheck --stacktrace
|
||||
|
8
.github/workflows/sanity_test.yml
vendored
8
.github/workflows/sanity_test.yml
vendored
@ -5,6 +5,12 @@ on:
|
||||
push:
|
||||
branches: [ main, develop ]
|
||||
|
||||
# Enrich gradle.properties for CI/CD
|
||||
env:
|
||||
CI_GRADLE_ARG_PROPERTIES: >
|
||||
-Porg.gradle.jvmargs=-Xmx2g
|
||||
-Porg.gradle.parallel=false
|
||||
|
||||
jobs:
|
||||
integration-tests:
|
||||
name: Sanity Tests (Synapse)
|
||||
@ -46,5 +52,5 @@ jobs:
|
||||
uses: reactivecircus/android-emulator-runner@v2
|
||||
with:
|
||||
api-level: ${{ matrix.api-level }}
|
||||
script: ./gradlew -PallWarningsAsErrors=false connectedGplayDebugAndroidTest -Pandroid.testInstrumentationRunnerArguments.class=im.vector.app.ui.UiAllScreensSanityTest
|
||||
script: ./gradlew $CI_GRADLE_ARG_PROPERTIES -PallWarningsAsErrors=false connectedGplayDebugAndroidTest -Pandroid.testInstrumentationRunnerArguments.class=im.vector.app.ui.UiAllScreensSanityTest
|
||||
|
||||
|
13
.github/workflows/tests.yml
vendored
13
.github/workflows/tests.yml
vendored
@ -5,6 +5,12 @@ on:
|
||||
push:
|
||||
branches: [main, develop]
|
||||
|
||||
# Enrich gradle.properties for CI/CD
|
||||
env:
|
||||
CI_GRADLE_ARG_PROPERTIES: >
|
||||
-Porg.gradle.jvmargs=-Xmx2g
|
||||
-Porg.gradle.parallel=false
|
||||
|
||||
jobs:
|
||||
unit-tests:
|
||||
name: Run Unit Tests
|
||||
@ -20,4 +26,9 @@ jobs:
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gradle-
|
||||
- name: Run unit tests
|
||||
run: ./gradlew clean test --stacktrace -PallWarningsAsErrors=false
|
||||
run: ./gradlew clean test $CI_GRADLE_ARG_PROPERTIES -PallWarningsAsErrors=false --stacktrace
|
||||
- name: Publish Unit Test Results
|
||||
uses: EnricoMi/publish-unit-test-result-action@v1
|
||||
if: always()
|
||||
with:
|
||||
files: ./**/build/test-results/**/*.xml
|
||||
|
59
CHANGES.md
59
CHANGES.md
@ -1,3 +1,62 @@
|
||||
Changes in Element v1.2.2 (2021-09-13)
|
||||
======================================
|
||||
|
||||
Bugfixes 🐛
|
||||
----------
|
||||
|
||||
- Fix a security issue with message key sharing. See https://matrix.org/blog/2021/09/13/vulnerability-disclosure-key-sharing for details.
|
||||
|
||||
|
||||
Changes in Element v1.2.1 (2021-09-08)
|
||||
======================================
|
||||
|
||||
Features ✨
|
||||
----------
|
||||
- Support Android 11 Conversation features ([#1809](https://github.com/vector-im/element-android/issues/1809))
|
||||
- Introduces AutoAcceptInvites which can be enabled at compile time. ([#3531](https://github.com/vector-im/element-android/issues/3531))
|
||||
- New call designs ([#3599](https://github.com/vector-im/element-android/issues/3599))
|
||||
- Restricted Join Rule | Inform admins of new option ([#3631](https://github.com/vector-im/element-android/issues/3631))
|
||||
- Mention and Keyword Notification Settings: Turn on/off keyword notifications and edit keywords. ([#3650](https://github.com/vector-im/element-android/issues/3650))
|
||||
- Support accept 3pid invite when email is not bound to account ([#3691](https://github.com/vector-im/element-android/issues/3691))
|
||||
- Space summary pagination ([#3693](https://github.com/vector-im/element-android/issues/3693))
|
||||
- Update Email invite to be aware of spaces ([#3695](https://github.com/vector-im/element-android/issues/3695))
|
||||
- M11.12 Spaces | Default to 'Home' in settings ([#3754](https://github.com/vector-im/element-android/issues/3754))
|
||||
- Call: show dialog for some ended reasons. ([#3853](https://github.com/vector-im/element-android/issues/3853))
|
||||
- Add expired account error code in the matrix SDK ([#3900](https://github.com/vector-im/element-android/issues/3900))
|
||||
- Add password errors in the matrix SDK ([#3927](https://github.com/vector-im/element-android/issues/3927))
|
||||
- Upgrade AGP to 7.0.2.
|
||||
When compiling using command line, make sure to use the JDK 11 by adding for instance `-Dorg.gradle.java.home=/Applications/Android\ Studio\ Preview.app/Contents/jre/Contents/Home` or by setting JAVA_HOME. ([#3954](https://github.com/vector-im/element-android/issues/3954))
|
||||
- Check power level before displaying actions in the room details' timeline ([#3959](https://github.com/vector-im/element-android/issues/3959))
|
||||
|
||||
Bugfixes 🐛
|
||||
----------
|
||||
- Add mxid to autocomplete suggestion if more than one user in a room has the same displayname ([#1823](https://github.com/vector-im/element-android/issues/1823))
|
||||
- Use WebView cache for widgets to avoid excessive data use ([#2648](https://github.com/vector-im/element-android/issues/2648))
|
||||
- Jitsi-hosted jitsi conferences not loading ([#2846](https://github.com/vector-im/element-android/issues/2846))
|
||||
- Space Explore Rooms no feedback on failed to join ([#3207](https://github.com/vector-im/element-android/issues/3207))
|
||||
- Notifications - Fix missing sound on notifications. ([#3243](https://github.com/vector-im/element-android/issues/3243))
|
||||
- the element-based domain permalinks (e.g. https://app.element.io/#/user/@chagai95:matrix.org) don't have the mxid in the first param (like matrix.to does - https://matrix.to/#/@chagai95:matrix.org) but rather in the second after /user/ so /user/mxid ([#3735](https://github.com/vector-im/element-android/issues/3735))
|
||||
- Update the AccountData with the users' matrix Id instead of their email for those invited by email in a direct chat ([#3743](https://github.com/vector-im/element-android/issues/3743))
|
||||
- Send an empty body for POST rooms/{roomId}/receipt/{receiptType}/{eventId} ([#3789](https://github.com/vector-im/element-android/issues/3789))
|
||||
- Fix order in which the items of the attachment menu appear ([#3793](https://github.com/vector-im/element-android/issues/3793))
|
||||
- Authenticated Jitsi not working in release ([#3841](https://github.com/vector-im/element-android/issues/3841))
|
||||
- Home: Dial pad lost entry when config changes ([#3845](https://github.com/vector-im/element-android/issues/3845))
|
||||
- Message edition is not rendered in e2e rooms after pagination ([#3887](https://github.com/vector-im/element-android/issues/3887))
|
||||
- Crash on opening a room on Android 5.0 and 5.1 - Regression with Voice message ([#3897](https://github.com/vector-im/element-android/issues/3897))
|
||||
- Fix a crash at start-up if translated string is empty ([#3910](https://github.com/vector-im/element-android/issues/3910))
|
||||
- PushRule enabling request is not following the spec ([#3911](https://github.com/vector-im/element-android/issues/3911))
|
||||
- Enable image preview in Android's share sheet (Android 11+) ([#3965](https://github.com/vector-im/element-android/issues/3965))
|
||||
- Voice Message - Cannot render voice message if the waveform data is corrupted ([#3983](https://github.com/vector-im/element-android/issues/3983))
|
||||
- Fix memory leak on RoomDetailFragment (ValueAnimator) ([#3990](https://github.com/vector-im/element-android/issues/3990))
|
||||
|
||||
Other changes
|
||||
-------------
|
||||
- VoIP: Merge virtual room timeline in corresponding native room (call events only). ([#3520](https://github.com/vector-im/element-android/issues/3520))
|
||||
- Issue templates: modernise and sync with element-web ([#3883](https://github.com/vector-im/element-android/issues/3883))
|
||||
- Issue templates: modernise SDK and release checklists, and add homeserver question for bugs ([#3889](https://github.com/vector-im/element-android/issues/3889))
|
||||
- Issue templates: merge expected and actual results ([#3960](https://github.com/vector-im/element-android/issues/3960))
|
||||
|
||||
|
||||
Changes in Element v1.2.0 (2021-08-12)
|
||||
======================================
|
||||
|
||||
|
@ -18,13 +18,12 @@ apply plugin: 'com.android.library'
|
||||
apply plugin: 'kotlin-android'
|
||||
|
||||
android {
|
||||
compileSdkVersion 30
|
||||
|
||||
compileSdk versions.compileSdk
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 30
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
minSdk versions.minSdk
|
||||
targetSdk versions.targetSdk
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
@ -34,8 +33,8 @@ android {
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_11
|
||||
targetCompatibility JavaVersion.VERSION_11
|
||||
sourceCompatibility versions.sourceCompat
|
||||
targetCompatibility versions.targetCompat
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = "11"
|
||||
@ -51,13 +50,13 @@ dependencies {
|
||||
|
||||
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 libs.rx.rxKotlin
|
||||
implementation libs.rx.rxAndroid
|
||||
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||
implementation 'androidx.core:core-ktx:1.6.0'
|
||||
implementation 'androidx.appcompat:appcompat:1.3.1'
|
||||
implementation "androidx.recyclerview:recyclerview:1.2.1"
|
||||
implementation libs.jetbrains.kotlinStdlib
|
||||
implementation libs.androidx.core
|
||||
implementation libs.androidx.appCompat
|
||||
implementation libs.androidx.recyclerview
|
||||
|
||||
implementation 'com.google.android.material:material:1.4.0'
|
||||
implementation libs.google.material
|
||||
}
|
11
build.gradle
11
build.gradle
@ -1,9 +1,9 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
|
||||
buildscript {
|
||||
// Ref: https://kotlinlang.org/releases.html
|
||||
ext.kotlin_version = '1.5.21'
|
||||
ext.kotlin_coroutines_version = "1.5.0"
|
||||
|
||||
apply from: 'dependencies.gradle'
|
||||
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
@ -11,12 +11,13 @@ buildscript {
|
||||
url "https://plugins.gradle.org/m2/"
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// Release notes of Android Gradle Plugin (AGP):
|
||||
// https://developer.android.com/studio/releases/gradle-plugin
|
||||
classpath 'com.android.tools.build:gradle:7.0.2'
|
||||
classpath libs.gradle.gradlePlugin
|
||||
classpath libs.gradle.kotlinPlugin
|
||||
classpath 'com.google.gms:google-services:4.3.10'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
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"
|
||||
|
@ -1 +0,0 @@
|
||||
Support Android 11 Conversation features
|
@ -1 +0,0 @@
|
||||
- Add mxid to autocomplete suggestion if more than one user in a room has the same displayname
|
@ -1 +0,0 @@
|
||||
Use WebView cache for widgets to avoid excessive data use
|
@ -1 +0,0 @@
|
||||
Jitsi-hosted jitsi conferences not loading
|
@ -1 +0,0 @@
|
||||
Space Explore Rooms no feedback on failed to join
|
@ -1 +0,0 @@
|
||||
Notifications - Fix missing sound on notifications.
|
@ -1 +0,0 @@
|
||||
VoIP: Merge virtual room timeline in corresponding native room (call events only).
|
@ -1 +0,0 @@
|
||||
Introduces AutoAcceptInvites which can be enabled at compile time.
|
@ -1 +0,0 @@
|
||||
New call designs
|
@ -1 +0,0 @@
|
||||
Restricted Join Rule | Inform admins of new option
|
@ -1 +0,0 @@
|
||||
Mention and Keyword Notification Settings: Turn on/off keyword notifications and edit keywords.
|
1
changelog.d/3678.feature
Normal file
1
changelog.d/3678.feature
Normal file
@ -0,0 +1 @@
|
||||
Spaces | M3.23 Invite by email in create private space flow
|
@ -1 +0,0 @@
|
||||
Support accept 3pid invite when email is not bound to account
|
1
changelog.d/3692.feature
Normal file
1
changelog.d/3692.feature
Normal file
@ -0,0 +1 @@
|
||||
Allow to also leave rooms when leaving a space
|
@ -1 +0,0 @@
|
||||
Space summary pagination
|
@ -1 +0,0 @@
|
||||
Update Email invite to be aware of spaces
|
@ -1 +0,0 @@
|
||||
the element-based domain permalinks (e.g. https://app.element.io/#/user/@chagai95:matrix.org) don't have the mxid in the first param (like matrix.to does - https://matrix.to/#/@chagai95:matrix.org) but rather in the second after /user/ so /user/mxid
|
@ -1 +0,0 @@
|
||||
Update the AccountData with the users' matrix Id instead of their email for those invited by email in a direct chat
|
1
changelog.d/3752.feature
Normal file
1
changelog.d/3752.feature
Normal file
@ -0,0 +1 @@
|
||||
Better expose adding spaces as Subspaces
|
@ -1 +0,0 @@
|
||||
M11.12 Spaces | Default to 'Home' in settings
|
@ -1 +0,0 @@
|
||||
Send an empty body for POST rooms/{roomId}/receipt/{receiptType}/{eventId}
|
@ -1 +0,0 @@
|
||||
Fix order in which the items of the attachement menu appear
|
@ -1 +0,0 @@
|
||||
Authenticated Jitsi not working in release
|
@ -1 +0,0 @@
|
||||
Home: Dial pad lost entry when config changes
|
@ -1 +0,0 @@
|
||||
Call: show dialog for some ended reasons.
|
@ -1 +0,0 @@
|
||||
Issue templates: modernise and sync with element-web
|
@ -1 +0,0 @@
|
||||
Message edition is not rendered in e2e rooms after pagination
|
@ -1 +0,0 @@
|
||||
Crash on opening a room on Android 5.0 and 5.1 - Regression with Voice message
|
@ -1 +0,0 @@
|
||||
Add expired account error code in the matrix SDK
|
@ -1 +0,0 @@
|
||||
Fix a crash at start-up if translated string is empty
|
@ -1 +0,0 @@
|
||||
PushRule enabling request is not following the spec
|
@ -1 +0,0 @@
|
||||
Add password errors in the matrix SDK
|
1
changelog.d/3945.bugfix
Normal file
1
changelog.d/3945.bugfix
Normal file
@ -0,0 +1 @@
|
||||
Remove the "Teammate spaces aren't quite ready" bottom sheet
|
1
changelog.d/3946.bugfix
Normal file
1
changelog.d/3946.bugfix
Normal file
@ -0,0 +1 @@
|
||||
Restricted Room previews aren't working
|
1
changelog.d/3947.bugfix
Normal file
1
changelog.d/3947.bugfix
Normal file
@ -0,0 +1 @@
|
||||
A removed room from a space can't be re-added as it won't be shown in add-room
|
1
changelog.d/3951.bugfix
Normal file
1
changelog.d/3951.bugfix
Normal file
@ -0,0 +1 @@
|
||||
"Non-Admin" user able to invite others to Private Space (by default)
|
@ -1,2 +0,0 @@
|
||||
Upgrade AGP to 7.0.2.
|
||||
When compiling using command line, make sure to use the JDK 11 by adding for instance `-Dorg.gradle.java.home=/Applications/Android\ Studio\ Preview.app/Contents/jre/Contents/Home` or by setting JAVA_HOME.
|
1
changelog.d/3956.bugfix
Normal file
1
changelog.d/3956.bugfix
Normal file
@ -0,0 +1 @@
|
||||
Kick user dialog for spaces talks about rooms
|
@ -1 +0,0 @@
|
||||
Check power level before displaying actions in the room details' timeline
|
@ -1 +0,0 @@
|
||||
Issue templates: merge expected and actual results
|
@ -1 +0,0 @@
|
||||
Enable image preview in Android's share sheet (Android 11+)
|
@ -1 +0,0 @@
|
||||
Voice Message - Cannot render voice message if the waveform data is corrupted
|
@ -1 +0,0 @@
|
||||
- Fix memory leak on RoomDetailFragment (ValueAnimator)
|
1
changelog.d/3994.misc
Normal file
1
changelog.d/3994.misc
Normal file
@ -0,0 +1 @@
|
||||
Better support for Sdk2 version. Also slight change in the default user agent: `MatrixAndroidSDK_X` is replaced by `MatrixAndroidSdk2`
|
1
changelog.d/4014.misc
Normal file
1
changelog.d/4014.misc
Normal file
@ -0,0 +1 @@
|
||||
Introduces ConferenceEvent to abstract usage of Jitsi BroadcastEvent class.
|
1
changelog.d/4015.bugfix
Normal file
1
changelog.d/4015.bugfix
Normal file
@ -0,0 +1 @@
|
||||
Fix DTMF not working
|
@ -1 +0,0 @@
|
||||
Issue templates: modernise SDK and release checklists, and add homeserver question for bugs
|
127
dependencies.gradle
Normal file
127
dependencies.gradle
Normal file
@ -0,0 +1,127 @@
|
||||
ext.versions = [
|
||||
|
||||
'minSdk' : 21,
|
||||
'compileSdk' : 30,
|
||||
'targetSdk' : 30,
|
||||
'sourceCompat' : JavaVersion.VERSION_11,
|
||||
'targetCompat' : JavaVersion.VERSION_11,
|
||||
]
|
||||
|
||||
// Ref: https://kotlinlang.org/releases.html
|
||||
def gradle = "7.0.2"
|
||||
def kotlin = "1.5.30"
|
||||
def kotlinCoroutines = "1.5.1"
|
||||
def dagger = "2.38.1"
|
||||
def retrofit = "2.9.0"
|
||||
def arrow = "0.8.2"
|
||||
def markwon = "4.6.2"
|
||||
def moshi = "1.12.0"
|
||||
def lifecycle = "2.2.0"
|
||||
def rxBinding = "3.1.0"
|
||||
def epoxy = "4.6.2"
|
||||
def glide = "4.12.0"
|
||||
def bigImageViewer = "1.8.1"
|
||||
def jjwt = "0.11.2"
|
||||
|
||||
// Testing
|
||||
def mockk = "1.12.0"
|
||||
def espresso = "3.4.0"
|
||||
def androidxTest = "1.4.0"
|
||||
|
||||
|
||||
ext.libs = [
|
||||
gradle : [
|
||||
'gradlePlugin' : "com.android.tools.build:gradle:$gradle",
|
||||
'kotlinPlugin' : "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin"
|
||||
],
|
||||
jetbrains : [
|
||||
'kotlinStdlibJdk7' : "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin",
|
||||
'kotlinStdlib' : "org.jetbrains.kotlin:kotlin-stdlib:$kotlin",
|
||||
'coroutinesCore' : "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinCoroutines",
|
||||
'coroutinesAndroid' : "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlinCoroutines",
|
||||
'coroutinesRx2' : "org.jetbrains.kotlinx:kotlinx-coroutines-rx2:$kotlinCoroutines"
|
||||
],
|
||||
androidx : [
|
||||
'appCompat' : "androidx.appcompat:appcompat:1.3.1",
|
||||
'core' : "androidx.core:core-ktx:1.6.0",
|
||||
'recyclerview' : "androidx.recyclerview:recyclerview:1.2.1",
|
||||
'exifinterface' : "androidx.exifinterface:exifinterface:1.3.3",
|
||||
'fragmentKtx' : "androidx.fragment:fragment-ktx:1.3.6",
|
||||
'constraintLayout' : "androidx.constraintlayout:constraintlayout:2.1.0",
|
||||
'work' : "androidx.work:work-runtime-ktx:2.5.0",
|
||||
'autoFill' : "androidx.autofill:autofill:1.1.0",
|
||||
'preferenceKtx' : "androidx.preference:preference-ktx:1.1.1",
|
||||
'junit' : "androidx.test.ext:junit:1.1.3",
|
||||
'lifecycleExtensions' : "androidx.lifecycle:lifecycle-extensions:$lifecycle",
|
||||
'lifecycleJava8' : "androidx.lifecycle:lifecycle-common-java8:$lifecycle",
|
||||
'lifecycleLivedata' : "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1",
|
||||
'pagingRuntimeKtx' : "androidx.paging:paging-runtime-ktx:2.1.2",
|
||||
'coreTesting' : "androidx.arch.core:core-testing:2.1.0",
|
||||
'testCore' : "androidx.test:core:$androidxTest",
|
||||
'testRunner' : "androidx.test:runner:$androidxTest",
|
||||
'testRules' : "androidx.test:rules:$androidxTest",
|
||||
'espressoCore' : "androidx.test.espresso:espresso-core:$espresso",
|
||||
'espressoContrib' : "androidx.test.espresso:espresso-contrib:$espresso",
|
||||
'espressoIntents' : "androidx.test.espresso:espresso-intents:$espresso"
|
||||
],
|
||||
google : [
|
||||
'material' : "com.google.android.material:material:1.4.0"
|
||||
],
|
||||
dagger : [
|
||||
'dagger' : "com.google.dagger:dagger:$dagger",
|
||||
'daggerCompiler' : "com.google.dagger:dagger-compiler:$dagger"
|
||||
],
|
||||
squareup : [
|
||||
'moshi' : "com.squareup.moshi:moshi-adapters:$moshi",
|
||||
'moshiKotlin' : "com.squareup.moshi:moshi-kotlin-codegen:$moshi",
|
||||
'retrofit' : "com.squareup.retrofit2:retrofit:$retrofit",
|
||||
'retrofitMoshi' : "com.squareup.retrofit2:converter-moshi:$retrofit"
|
||||
],
|
||||
rx : [
|
||||
'rxKotlin' : "io.reactivex.rxjava2:rxkotlin:2.4.0",
|
||||
'rxAndroid' : "io.reactivex.rxjava2:rxandroid:2.1.1"
|
||||
],
|
||||
arrow : [
|
||||
'core' : "io.arrow-kt:arrow-core:$arrow",
|
||||
'instances' : "io.arrow-kt:arrow-instances-core:$arrow"
|
||||
],
|
||||
markwon : [
|
||||
'core' : "io.noties.markwon:core:$markwon",
|
||||
'html' : "io.noties.markwon:html:$markwon"
|
||||
],
|
||||
airbnb : [
|
||||
'epoxy' : "com.airbnb.android:epoxy:$epoxy",
|
||||
'epoxyGlide' : "com.airbnb.android:epoxy-glide-preloading:$epoxy",
|
||||
'epoxyProcessor' : "com.airbnb.android:epoxy-processor:$epoxy",
|
||||
'epoxyPaging' : "com.airbnb.android:epoxy-paging:$epoxy",
|
||||
'mvrx' : "com.airbnb.android:mvrx:1.5.1"
|
||||
],
|
||||
mockk : [
|
||||
'mockk' : "io.mockk:mockk:$mockk",
|
||||
'mockkAndroid' : "io.mockk:mockk-android:$mockk"
|
||||
],
|
||||
github : [
|
||||
'glide' : "com.github.bumptech.glide:glide:$glide",
|
||||
'glideCompiler' : "com.github.bumptech.glide:compiler:$glide",
|
||||
'bigImageViewer' : "com.github.piasy:BigImageViewer:$bigImageViewer",
|
||||
'glideImageLoader' : "com.github.piasy:GlideImageLoader:$bigImageViewer",
|
||||
'progressPieIndicator' : "com.github.piasy:ProgressPieIndicator:$bigImageViewer",
|
||||
'glideImageViewFactory' : "com.github.piasy:GlideImageViewFactory:$bigImageViewer"
|
||||
],
|
||||
jakewharton : [
|
||||
'timber' : "com.jakewharton.timber:timber:5.0.1",
|
||||
'rxbinding' : "com.jakewharton.rxbinding3:rxbinding:$rxBinding",
|
||||
'rxbindingAppcompat' : "com.jakewharton.rxbinding3:rxbinding-appcompat:$rxBinding",
|
||||
'rxbindingMaterial' : "com.jakewharton.rxbinding3:rxbinding-material:$rxBinding"
|
||||
],
|
||||
jsonwebtoken: [
|
||||
'jjwtApi' : "io.jsonwebtoken:jjwt-api:$jjwt",
|
||||
'jjwtImpl' : "io.jsonwebtoken:jjwt-impl:$jjwt",
|
||||
'jjwtOrgjson' : "io.jsonwebtoken:jjwt-orgjson:$jjwt"
|
||||
],
|
||||
tests : [
|
||||
'kluent' : "org.amshove.kluent:kluent-android:1.68",
|
||||
'timberJunitRule' : "net.lachlanmckee:timber-junit-rule:1.0.1",
|
||||
'junit' : "junit:junit:4.13.2"
|
||||
]
|
||||
]
|
@ -1,2 +1,2 @@
|
||||
Main changes in this version: Voice Message is enabled by default.
|
||||
Full changelog: https://github.com/vector-im/element-android/releases/tag/v1.1.16
|
||||
Full changelog: https://github.com/vector-im/element-android/releases/tag/v1.2.0
|
2
fastlane/metadata/android/en-US/changelogs/40102010.txt
Normal file
2
fastlane/metadata/android/en-US/changelogs/40102010.txt
Normal file
@ -0,0 +1,2 @@
|
||||
Main changes in this version: Many improvements on VoIP and Spaces (still in beta).
|
||||
Full changelog: https://github.com/vector-im/element-android/releases/tag/v1.2.1
|
@ -6,20 +6,20 @@
|
||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
# The setting is particularly useful for tweaking memory settings.
|
||||
android.enableJetifier=true
|
||||
android.useAndroidX=true
|
||||
org.gradle.jvmargs=-Xmx2048m
|
||||
# When configured, Gradle will run in incubating parallel mode.
|
||||
# This option should only be used with decoupled projects. More details, visit
|
||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
# org.gradle.parallel=true
|
||||
|
||||
# Enable file system watch (https://docs.gradle.org/6.7/release-notes.html)
|
||||
# Build Time Optimizations
|
||||
org.gradle.jvmargs=-Xmx3g -Xms512M -XX:MaxPermSize=2048m -XX:MaxMetaspaceSize=1g -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 -XX:+UseParallelGC
|
||||
org.gradle.configureondemand=true
|
||||
org.gradle.parallel=true
|
||||
org.gradle.vfs.watch=true
|
||||
|
||||
# Android Settings
|
||||
android.enableJetifier=true
|
||||
android.useAndroidX=true
|
||||
|
||||
#Project Settings
|
||||
# Change debugPrivateData to true for debugging
|
||||
vector.debugPrivateData=false
|
||||
# httpLogLevel values: NONE, BASIC, HEADERS, BODY
|
||||
vector.httpLogLevel=BASIC
|
||||
|
||||
# Note: to debug, you can put and uncomment the following lines in the file ~/.gradle/gradle.properties to override the value above
|
||||
#vector.debugPrivateData=true
|
||||
#vector.httpLogLevel=BODY
|
||||
|
@ -20,14 +20,11 @@ plugins {
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 30
|
||||
buildToolsVersion "30.0.3"
|
||||
|
||||
compileSdk versions.compileSdk
|
||||
defaultConfig {
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 30
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
minSdk versions.minSdk
|
||||
targetSdk versions.targetSdk
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
consumerProguardFiles "consumer-rules.pro"
|
||||
@ -41,8 +38,8 @@ android {
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_11
|
||||
targetCompatibility JavaVersion.VERSION_11
|
||||
sourceCompatibility versions.sourceCompat
|
||||
targetCompatibility versions.targetCompat
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
@ -55,10 +52,10 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'androidx.appcompat:appcompat:1.3.1'
|
||||
implementation 'com.google.android.material:material:1.4.0'
|
||||
implementation libs.androidx.appCompat
|
||||
implementation libs.google.material
|
||||
// Pref theme
|
||||
implementation 'androidx.preference:preference-ktx:1.1.1'
|
||||
implementation libs.androidx.preferenceKtx
|
||||
// PFLockScreen attrs
|
||||
implementation 'com.github.vector-im:PFLockScreen-Android:1.0.0-beta12'
|
||||
// dialpad dimen
|
||||
|
@ -8,6 +8,7 @@
|
||||
<attr name="actionDescription" format="string" />
|
||||
<attr name="leftIcon" format="reference" />
|
||||
<attr name="rightIcon" format="reference" />
|
||||
<attr name="betaAction" format="boolean" />
|
||||
<attr name="forceStartPadding" format="boolean" />
|
||||
</declare-styleable>
|
||||
|
||||
|
@ -3,13 +3,11 @@ apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-kapt'
|
||||
|
||||
android {
|
||||
compileSdkVersion 30
|
||||
compileSdk versions.compileSdk
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 30
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
minSdk versions.minSdk
|
||||
targetSdk versions.targetSdk
|
||||
|
||||
// Multidex is useful for tests
|
||||
multiDexEnabled true
|
||||
@ -24,8 +22,8 @@ android {
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_11
|
||||
targetCompatibility JavaVersion.VERSION_11
|
||||
sourceCompatibility versions.sourceCompat
|
||||
targetCompatibility versions.targetCompat
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
@ -34,15 +32,16 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
implementation project(":matrix-sdk-android")
|
||||
implementation 'androidx.appcompat:appcompat:1.3.1'
|
||||
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"
|
||||
implementation libs.androidx.appCompat
|
||||
implementation libs.rx.rxKotlin
|
||||
implementation libs.rx.rxAndroid
|
||||
implementation libs.jetbrains.coroutinesRx2
|
||||
|
||||
// Paging
|
||||
implementation "androidx.paging:paging-runtime-ktx:2.1.2"
|
||||
implementation libs.androidx.pagingRuntimeKtx
|
||||
|
||||
// Logging
|
||||
implementation 'com.jakewharton.timber:timber:5.0.1'
|
||||
implementation libs.jakewharton.timber
|
||||
}
|
||||
|
@ -14,14 +14,14 @@ buildscript {
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 30
|
||||
testOptions.unitTests.includeAndroidResources = true
|
||||
|
||||
compileSdk versions.compileSdk
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 30
|
||||
versionCode 1
|
||||
versionName "0.0.1"
|
||||
minSdk versions.minSdk
|
||||
targetSdk versions.targetSdk
|
||||
|
||||
// Multidex is useful for tests
|
||||
multiDexEnabled true
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
@ -31,9 +31,7 @@ android {
|
||||
// that the app's state is completely cleared between tests.
|
||||
testInstrumentationRunnerArguments clearPackageData: 'true'
|
||||
|
||||
// Seems that the build tools 4.1.0 does not generate BuildConfig.VERSION_NAME anymore.
|
||||
// Add it manually here. We may remove this trick in the future
|
||||
buildConfigField "String", "VERSION_NAME", "\"0.0.1\""
|
||||
buildConfigField "String", "SDK_VERSION", "\"1.2.2\""
|
||||
|
||||
buildConfigField "String", "GIT_SDK_REVISION", "\"${gitRevision()}\""
|
||||
resValue "string", "git_sdk_revision", "\"${gitRevision()}\""
|
||||
@ -68,8 +66,8 @@ android {
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_11
|
||||
targetCompatibility JavaVersion.VERSION_11
|
||||
sourceCompatibility versions.sourceCompat
|
||||
targetCompatibility versions.targetCompat
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
@ -103,92 +101,83 @@ static def gitRevisionDate() {
|
||||
|
||||
dependencies {
|
||||
|
||||
def arrow_version = "0.8.2"
|
||||
def moshi_version = '1.12.0'
|
||||
def lifecycle_version = '2.2.0'
|
||||
def arch_version = '2.1.0'
|
||||
def markwon_version = '3.1.0'
|
||||
def daggerVersion = '2.38.1'
|
||||
def work_version = '2.5.0'
|
||||
def retrofit_version = '2.9.0'
|
||||
implementation libs.jetbrains.kotlinStdlibJdk7
|
||||
implementation libs.jetbrains.coroutinesCore
|
||||
implementation libs.jetbrains.coroutinesAndroid
|
||||
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version"
|
||||
implementation libs.androidx.appCompat
|
||||
implementation libs.androidx.core
|
||||
|
||||
implementation "androidx.appcompat:appcompat:1.3.1"
|
||||
implementation "androidx.core:core-ktx:1.6.0"
|
||||
|
||||
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
|
||||
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
|
||||
implementation libs.androidx.lifecycleExtensions
|
||||
implementation libs.androidx.lifecycleJava8
|
||||
|
||||
// Network
|
||||
implementation "com.squareup.retrofit2:retrofit:$retrofit_version"
|
||||
implementation "com.squareup.retrofit2:converter-moshi:$retrofit_version"
|
||||
implementation libs.squareup.retrofit
|
||||
implementation libs.squareup.retrofitMoshi
|
||||
|
||||
implementation(platform("com.squareup.okhttp3:okhttp-bom:4.9.1"))
|
||||
implementation 'com.squareup.okhttp3:okhttp'
|
||||
implementation 'com.squareup.okhttp3:logging-interceptor'
|
||||
implementation 'com.squareup.okhttp3:okhttp-urlconnection'
|
||||
|
||||
implementation "com.squareup.moshi:moshi-adapters:$moshi_version"
|
||||
kapt "com.squareup.moshi:moshi-kotlin-codegen:$moshi_version"
|
||||
implementation libs.squareup.moshi
|
||||
kapt libs.squareup.moshiKotlin
|
||||
|
||||
implementation "ru.noties.markwon:core:$markwon_version"
|
||||
implementation libs.markwon.core
|
||||
|
||||
// Image
|
||||
implementation 'androidx.exifinterface:exifinterface:1.3.3'
|
||||
implementation libs.androidx.exifinterface
|
||||
|
||||
// Database
|
||||
implementation 'com.github.Zhuinden:realm-monarchy:0.7.1'
|
||||
kapt 'dk.ilios:realmfieldnameshelper:2.0.0'
|
||||
|
||||
// Work
|
||||
implementation "androidx.work:work-runtime-ktx:$work_version"
|
||||
implementation libs.androidx.work
|
||||
|
||||
// FP
|
||||
implementation "io.arrow-kt:arrow-core:$arrow_version"
|
||||
implementation "io.arrow-kt:arrow-instances-core:$arrow_version"
|
||||
implementation libs.arrow.core
|
||||
implementation libs.arrow.instances
|
||||
|
||||
// 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.4'
|
||||
|
||||
// DI
|
||||
implementation "com.google.dagger:dagger:$daggerVersion"
|
||||
kapt "com.google.dagger:dagger-compiler:$daggerVersion"
|
||||
implementation libs.dagger.dagger
|
||||
kapt libs.dagger.daggerCompiler
|
||||
|
||||
// Logging
|
||||
implementation 'com.jakewharton.timber:timber:5.0.1'
|
||||
implementation libs.jakewharton.timber
|
||||
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.31'
|
||||
implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.32'
|
||||
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
testImplementation 'org.robolectric:robolectric:4.5.1'
|
||||
testImplementation libs.tests.junit
|
||||
testImplementation 'org.robolectric:robolectric:4.6.1'
|
||||
//testImplementation 'org.robolectric:shadows-support-v4:3.0'
|
||||
// Note: version sticks to 1.9.2 due to https://github.com/mockk/mockk/issues/281
|
||||
testImplementation 'io.mockk:mockk:1.12.0'
|
||||
testImplementation 'org.amshove.kluent:kluent-android:1.68'
|
||||
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version"
|
||||
testImplementation libs.mockk.mockk
|
||||
testImplementation libs.tests.kluent
|
||||
implementation libs.jetbrains.coroutinesAndroid
|
||||
// Plant Timber tree for test
|
||||
testImplementation 'net.lachlanmckee:timber-junit-rule:1.0.1'
|
||||
|
||||
kaptAndroidTest "com.google.dagger:dagger-compiler:$daggerVersion"
|
||||
androidTestImplementation 'androidx.test:core:1.4.0'
|
||||
androidTestImplementation 'androidx.test:runner:1.4.0'
|
||||
androidTestImplementation 'androidx.test:rules:1.4.0'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
|
||||
androidTestImplementation 'org.amshove.kluent:kluent-android:1.68'
|
||||
androidTestImplementation 'io.mockk:mockk-android:1.12.0'
|
||||
androidTestImplementation "androidx.arch.core:core-testing:$arch_version"
|
||||
androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version"
|
||||
kaptAndroidTest libs.dagger.daggerCompiler
|
||||
androidTestImplementation libs.androidx.testCore
|
||||
androidTestImplementation libs.androidx.testRunner
|
||||
androidTestImplementation libs.androidx.testRules
|
||||
androidTestImplementation libs.androidx.junit
|
||||
androidTestImplementation libs.androidx.espressoCore
|
||||
androidTestImplementation libs.tests.kluent
|
||||
androidTestImplementation libs.mockk.mockkAndroid
|
||||
androidTestImplementation libs.androidx.coreTesting
|
||||
androidTestImplementation libs.jetbrains.coroutinesAndroid
|
||||
// Plant Timber tree for test
|
||||
androidTestImplementation 'net.lachlanmckee:timber-junit-rule:1.0.1'
|
||||
androidTestImplementation libs.tests.timberJunitRule
|
||||
|
||||
androidTestUtil 'androidx.test:orchestrator:1.4.0'
|
||||
}
|
||||
|
@ -117,7 +117,7 @@ class Matrix private constructor(context: Context, matrixConfiguration: MatrixCo
|
||||
}
|
||||
|
||||
fun getSdkVersion(): String {
|
||||
return BuildConfig.VERSION_NAME + " (" + BuildConfig.GIT_SDK_REVISION + ")"
|
||||
return BuildConfig.SDK_VERSION + " (" + BuildConfig.GIT_SDK_REVISION + ")"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,8 @@ package org.matrix.android.sdk.common
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.test.internal.runner.junit4.statement.UiThreadStatement
|
||||
import androidx.test.internal.runner.junit4.statement.UiThreadStatement.runOnUiThread
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.delay
|
||||
@ -59,13 +61,15 @@ class CommonTestHelper(context: Context) {
|
||||
fun getTestInterceptor(session: Session): MockOkHttpInterceptor? = TestNetworkModule.interceptorForSession(session.sessionId) as? MockOkHttpInterceptor
|
||||
|
||||
init {
|
||||
Matrix.initialize(
|
||||
context,
|
||||
MatrixConfiguration(
|
||||
applicationFlavor = "TestFlavor",
|
||||
roomDisplayNameFallbackProvider = TestRoomDisplayNameFallbackProvider()
|
||||
)
|
||||
)
|
||||
UiThreadStatement.runOnUiThread {
|
||||
Matrix.initialize(
|
||||
context,
|
||||
MatrixConfiguration(
|
||||
applicationFlavor = "TestFlavor",
|
||||
roomDisplayNameFallbackProvider = TestRoomDisplayNameFallbackProvider()
|
||||
)
|
||||
)
|
||||
}
|
||||
matrix = Matrix.getInstance(context)
|
||||
}
|
||||
|
||||
|
@ -32,10 +32,19 @@ import org.junit.runners.JUnit4
|
||||
import org.junit.runners.MethodSorters
|
||||
import org.matrix.android.sdk.InstrumentedTest
|
||||
import org.matrix.android.sdk.api.query.ActiveSpaceFilter
|
||||
import org.matrix.android.sdk.api.query.QueryStringValue
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||
import org.matrix.android.sdk.api.session.events.model.toContent
|
||||
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesAllowEntry
|
||||
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.model.create.RestrictedRoomPreset
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.Role
|
||||
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
|
||||
import org.matrix.android.sdk.common.CommonTestHelper
|
||||
import org.matrix.android.sdk.common.SessionTestParams
|
||||
@ -386,6 +395,8 @@ class SpaceHierarchyTest : InstrumentedTest {
|
||||
// The room should have disapear from flat children
|
||||
GlobalScope.launch(Dispatchers.Main) { flatAChildren.observeForever(childObserver) }
|
||||
}
|
||||
|
||||
commonTestHelper.signOutAndClose(session)
|
||||
}
|
||||
|
||||
data class TestSpaceCreationResult(
|
||||
@ -434,6 +445,57 @@ class SpaceHierarchyTest : InstrumentedTest {
|
||||
return TestSpaceCreationResult(spaceId, roomIds)
|
||||
}
|
||||
|
||||
@Suppress("EXPERIMENTAL_API_USAGE")
|
||||
private fun createPrivateSpace(session: Session,
|
||||
spaceName: String,
|
||||
childInfo: List<Triple<String, Boolean, Boolean?>>
|
||||
/** Name, auto-join, canonical*/
|
||||
): TestSpaceCreationResult {
|
||||
var spaceId = ""
|
||||
commonTestHelper.waitWithLatch {
|
||||
GlobalScope.launch {
|
||||
spaceId = session.spaceService().createSpace(spaceName, "My Private Space", null, false)
|
||||
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 {
|
||||
val homeServerCapabilities = session
|
||||
.getHomeServerCapabilities()
|
||||
roomId = session.createRoom(CreateRoomParams().apply {
|
||||
name = entry.first
|
||||
this.featurePreset = RestrictedRoomPreset(
|
||||
homeServerCapabilities,
|
||||
listOf(
|
||||
RoomJoinRulesAllowEntry.restrictedToRoom(spaceId)
|
||||
)
|
||||
)
|
||||
})
|
||||
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))
|
||||
@ -473,5 +535,111 @@ class SpaceHierarchyTest : InstrumentedTest {
|
||||
val rootSpaces = session.spaceService().getRootSpaceSummaries()
|
||||
|
||||
assertEquals("Unexpected number of root spaces ${rootSpaces.map { it.name }}", 2, rootSpaces.size)
|
||||
|
||||
commonTestHelper.signOutAndClose(session)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testParentRelation() {
|
||||
val aliceSession = commonTestHelper.createAccount("Alice", SessionTestParams(true))
|
||||
val bobSession = commonTestHelper.createAccount("Bib", SessionTestParams(true))
|
||||
|
||||
val spaceAInfo = createPrivateSpace(aliceSession, "Private Space A", listOf(
|
||||
Triple("General", true /*suggested*/, true/*canonical*/),
|
||||
Triple("Random", true, true)
|
||||
))
|
||||
|
||||
commonTestHelper.runBlockingTest {
|
||||
aliceSession.getRoom(spaceAInfo.spaceId)!!.invite(bobSession.myUserId, null)
|
||||
}
|
||||
|
||||
commonTestHelper.runBlockingTest {
|
||||
bobSession.joinRoom(spaceAInfo.spaceId, null, emptyList())
|
||||
}
|
||||
|
||||
var bobRoomId = ""
|
||||
commonTestHelper.waitWithLatch {
|
||||
GlobalScope.launch {
|
||||
bobRoomId = bobSession.createRoom(CreateRoomParams().apply { name = "A Bob Room" })
|
||||
bobSession.getRoom(bobRoomId)!!.invite(aliceSession.myUserId)
|
||||
it.countDown()
|
||||
}
|
||||
}
|
||||
|
||||
commonTestHelper.runBlockingTest {
|
||||
aliceSession.joinRoom(bobRoomId)
|
||||
}
|
||||
|
||||
commonTestHelper.waitWithLatch { latch ->
|
||||
commonTestHelper.retryPeriodicallyWithLatch(latch) {
|
||||
aliceSession.getRoomSummary(bobRoomId)?.membership?.isActive() == true
|
||||
}
|
||||
}
|
||||
|
||||
commonTestHelper.waitWithLatch {
|
||||
GlobalScope.launch {
|
||||
bobSession.spaceService().setSpaceParent(bobRoomId, spaceAInfo.spaceId, false, listOf(bobSession.sessionParams.homeServerHost ?: ""))
|
||||
it.countDown()
|
||||
}
|
||||
}
|
||||
|
||||
commonTestHelper.waitWithLatch { latch ->
|
||||
commonTestHelper.retryPeriodicallyWithLatch(latch) {
|
||||
val stateEvent = aliceSession.getRoom(bobRoomId)!!.getStateEvent(EventType.STATE_SPACE_PARENT, QueryStringValue.Equals(spaceAInfo.spaceId))
|
||||
stateEvent != null
|
||||
}
|
||||
}
|
||||
|
||||
// This should be an invalid space parent relation, because no opposite child and bob is not admin of the space
|
||||
commonTestHelper.runBlockingTest {
|
||||
// we can see the state event
|
||||
// but it is not valid and room is not in hierarchy
|
||||
assertTrue("Bob Room should not be listed as a child of the space", aliceSession.getRoomSummary(bobRoomId)?.flattenParentIds?.isEmpty() == true)
|
||||
}
|
||||
|
||||
// Let's now try to make alice admin of the room
|
||||
|
||||
commonTestHelper.waitWithLatch {
|
||||
GlobalScope.launch {
|
||||
val room = bobSession.getRoom(bobRoomId)!!
|
||||
val currentPLContent = room
|
||||
.getStateEvent(EventType.STATE_ROOM_POWER_LEVELS)
|
||||
?.let { it.content.toModel<PowerLevelsContent>() }
|
||||
|
||||
val newPowerLevelsContent = currentPLContent
|
||||
?.setUserPowerLevel(aliceSession.myUserId, Role.Admin.value)
|
||||
?.toContent()
|
||||
|
||||
room.sendStateEvent(EventType.STATE_ROOM_POWER_LEVELS, null, newPowerLevelsContent!!)
|
||||
it.countDown()
|
||||
}
|
||||
}
|
||||
|
||||
commonTestHelper.waitWithLatch { latch ->
|
||||
commonTestHelper.retryPeriodicallyWithLatch(latch) {
|
||||
val powerLevelsHelper = aliceSession.getRoom(bobRoomId)!!
|
||||
.getStateEvent(EventType.STATE_ROOM_POWER_LEVELS)
|
||||
?.content
|
||||
?.toModel<PowerLevelsContent>()
|
||||
?.let { PowerLevelsHelper(it) }
|
||||
powerLevelsHelper!!.isUserAllowedToSend(aliceSession.myUserId, true, EventType.STATE_SPACE_PARENT)
|
||||
}
|
||||
}
|
||||
|
||||
commonTestHelper.waitWithLatch {
|
||||
GlobalScope.launch {
|
||||
aliceSession.spaceService().setSpaceParent(bobRoomId, spaceAInfo.spaceId, false, listOf(bobSession.sessionParams.homeServerHost ?: ""))
|
||||
it.countDown()
|
||||
}
|
||||
}
|
||||
|
||||
commonTestHelper.waitWithLatch { latch ->
|
||||
commonTestHelper.retryPeriodicallyWithLatch(latch) {
|
||||
bobSession.getRoomSummary(bobRoomId)?.flattenParentIds?.contains(spaceAInfo.spaceId) == true
|
||||
}
|
||||
}
|
||||
|
||||
commonTestHelper.signOutAndClose(aliceSession)
|
||||
commonTestHelper.signOutAndClose(bobSession)
|
||||
}
|
||||
}
|
||||
|
@ -111,7 +111,7 @@ class Matrix private constructor(context: Context, matrixConfiguration: MatrixCo
|
||||
}
|
||||
|
||||
fun getSdkVersion(): String {
|
||||
return BuildConfig.VERSION_NAME + " (" + BuildConfig.GIT_SDK_REVISION + ")"
|
||||
return BuildConfig.SDK_VERSION + " (" + BuildConfig.GIT_SDK_REVISION + ")"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -239,7 +239,7 @@ data class Event(
|
||||
|
||||
fun Event.isTextMessage(): Boolean {
|
||||
return getClearType() == EventType.MESSAGE
|
||||
&& when (getClearContent()?.toModel<MessageContent>()?.msgType) {
|
||||
&& when (getClearContent()?.get(MessageContent.MSG_TYPE_JSON_KEY)) {
|
||||
MessageType.MSGTYPE_TEXT,
|
||||
MessageType.MSGTYPE_EMOTE,
|
||||
MessageType.MSGTYPE_NOTICE -> true
|
||||
@ -249,7 +249,7 @@ fun Event.isTextMessage(): Boolean {
|
||||
|
||||
fun Event.isImageMessage(): Boolean {
|
||||
return getClearType() == EventType.MESSAGE
|
||||
&& when (getClearContent()?.toModel<MessageContent>()?.msgType) {
|
||||
&& when (getClearContent()?.get(MessageContent.MSG_TYPE_JSON_KEY)) {
|
||||
MessageType.MSGTYPE_IMAGE -> true
|
||||
else -> false
|
||||
}
|
||||
@ -257,7 +257,7 @@ fun Event.isImageMessage(): Boolean {
|
||||
|
||||
fun Event.isVideoMessage(): Boolean {
|
||||
return getClearType() == EventType.MESSAGE
|
||||
&& when (getClearContent()?.toModel<MessageContent>()?.msgType) {
|
||||
&& when (getClearContent()?.get(MessageContent.MSG_TYPE_JSON_KEY)) {
|
||||
MessageType.MSGTYPE_VIDEO -> true
|
||||
else -> false
|
||||
}
|
||||
@ -265,7 +265,7 @@ fun Event.isVideoMessage(): Boolean {
|
||||
|
||||
fun Event.isAudioMessage(): Boolean {
|
||||
return getClearType() == EventType.MESSAGE
|
||||
&& when (getClearContent()?.toModel<MessageContent>()?.msgType) {
|
||||
&& when (getClearContent()?.get(MessageContent.MSG_TYPE_JSON_KEY)) {
|
||||
MessageType.MSGTYPE_AUDIO -> true
|
||||
else -> false
|
||||
}
|
||||
@ -273,7 +273,7 @@ fun Event.isAudioMessage(): Boolean {
|
||||
|
||||
fun Event.isFileMessage(): Boolean {
|
||||
return getClearType() == EventType.MESSAGE
|
||||
&& when (getClearContent()?.toModel<MessageContent>()?.msgType) {
|
||||
&& when (getClearContent()?.get(MessageContent.MSG_TYPE_JSON_KEY)) {
|
||||
MessageType.MSGTYPE_FILE -> true
|
||||
else -> false
|
||||
}
|
||||
@ -281,7 +281,7 @@ fun Event.isFileMessage(): Boolean {
|
||||
|
||||
fun Event.isAttachmentMessage(): Boolean {
|
||||
return getClearType() == EventType.MESSAGE
|
||||
&& when (getClearContent()?.toModel<MessageContent>()?.msgType) {
|
||||
&& when (getClearContent()?.get(MessageContent.MSG_TYPE_JSON_KEY)) {
|
||||
MessageType.MSGTYPE_IMAGE,
|
||||
MessageType.MSGTYPE_AUDIO,
|
||||
MessageType.MSGTYPE_VIDEO,
|
||||
|
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
/**
|
||||
* These are the same fields as those returned by /publicRooms, with a few additions: room_type, membership and is_encrypted.
|
||||
*/
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class RoomStrippedState(
|
||||
/**
|
||||
* Aliases of the room. May be empty.
|
||||
*/
|
||||
@Json(name = "aliases")
|
||||
val aliases: List<String>? = null,
|
||||
|
||||
/**
|
||||
* The canonical alias of the room, if any.
|
||||
*/
|
||||
@Json(name = "canonical_alias")
|
||||
val canonicalAlias: String? = null,
|
||||
|
||||
/**
|
||||
* The name of the room, if any.
|
||||
*/
|
||||
@Json(name = "name")
|
||||
val name: String? = null,
|
||||
|
||||
/**
|
||||
* Required. The number of members joined to the room.
|
||||
*/
|
||||
@Json(name = "num_joined_members")
|
||||
val numJoinedMembers: Int = 0,
|
||||
|
||||
/**
|
||||
* Required. The ID of the room.
|
||||
*/
|
||||
@Json(name = "room_id")
|
||||
val roomId: String,
|
||||
|
||||
/**
|
||||
* The topic of the room, if any.
|
||||
*/
|
||||
@Json(name = "topic")
|
||||
val topic: String? = null,
|
||||
|
||||
/**
|
||||
* Required. Whether the room may be viewed by guest users without joining.
|
||||
*/
|
||||
@Json(name = "world_readable")
|
||||
val worldReadable: Boolean = false,
|
||||
|
||||
/**
|
||||
* Required. Whether guest users may join the room and participate in it. If they can,
|
||||
* they will be subject to ordinary power level rules like any other user.
|
||||
*/
|
||||
@Json(name = "guest_can_join")
|
||||
val guestCanJoin: Boolean = false,
|
||||
|
||||
/**
|
||||
* The URL for the room's avatar, if one is set.
|
||||
*/
|
||||
@Json(name = "avatar_url")
|
||||
val avatarUrl: String? = null,
|
||||
|
||||
/**
|
||||
* Undocumented item
|
||||
*/
|
||||
@Json(name = "m.federate")
|
||||
val isFederated: Boolean = false,
|
||||
|
||||
/**
|
||||
* Optional. If the room is encrypted. This is already accessible as stripped state.
|
||||
*/
|
||||
@Json(name = "is_encrypted")
|
||||
val isEncrypted: Boolean?,
|
||||
|
||||
/**
|
||||
* Optional. Type of the room, if any, i.e. m.space
|
||||
*/
|
||||
@Json(name = "room_type")
|
||||
val roomType: String?,
|
||||
|
||||
/**
|
||||
* The current membership of this user in the room. Usually leave if the room is fetched over federation.
|
||||
*/
|
||||
@Json(name = "membership")
|
||||
val membership: String?
|
||||
) {
|
||||
/**
|
||||
* Return the canonical alias, or the first alias from the list of aliases, or null
|
||||
*/
|
||||
fun getPrimaryAlias(): String? {
|
||||
return canonicalAlias ?: aliases?.firstOrNull()
|
||||
}
|
||||
}
|
@ -28,7 +28,7 @@ data class MessageAudioContent(
|
||||
/**
|
||||
* Required. Must be 'm.audio'.
|
||||
*/
|
||||
@Json(name = "msgtype") override val msgType: String,
|
||||
@Json(name = MessageContent.MSG_TYPE_JSON_KEY) override val msgType: String,
|
||||
|
||||
/**
|
||||
* Required. A description of the audio e.g. 'Bee Gees - Stayin' Alive', or some kind of content description for accessibility e.g. 'audio attachment'.
|
||||
|
@ -20,6 +20,11 @@ import org.matrix.android.sdk.api.session.events.model.Content
|
||||
import org.matrix.android.sdk.api.session.room.model.relation.RelationDefaultContent
|
||||
|
||||
interface MessageContent {
|
||||
|
||||
companion object {
|
||||
const val MSG_TYPE_JSON_KEY = "msgtype"
|
||||
}
|
||||
|
||||
val msgType: String
|
||||
val body: String
|
||||
val relatesTo: RelationDefaultContent?
|
||||
|
@ -23,7 +23,7 @@ import org.matrix.android.sdk.api.session.room.model.relation.RelationDefaultCon
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class MessageDefaultContent(
|
||||
@Json(name = "msgtype") override val msgType: String,
|
||||
@Json(name = MessageContent.MSG_TYPE_JSON_KEY) override val msgType: String,
|
||||
@Json(name = "body") override val body: String,
|
||||
@Json(name = "m.relates_to") override val relatesTo: RelationDefaultContent? = null,
|
||||
@Json(name = "m.new_content") override val newContent: Content? = null
|
||||
|
@ -26,7 +26,7 @@ data class MessageEmoteContent(
|
||||
/**
|
||||
* Required. Must be 'm.emote'.
|
||||
*/
|
||||
@Json(name = "msgtype") override val msgType: String,
|
||||
@Json(name = MessageContent.MSG_TYPE_JSON_KEY) override val msgType: String,
|
||||
|
||||
/**
|
||||
* Required. The emote action to perform.
|
||||
|
@ -28,7 +28,7 @@ data class MessageFileContent(
|
||||
/**
|
||||
* Required. Must be 'm.file'.
|
||||
*/
|
||||
@Json(name = "msgtype") override val msgType: String,
|
||||
@Json(name = MessageContent.MSG_TYPE_JSON_KEY) override val msgType: String,
|
||||
|
||||
/**
|
||||
* Required. A human-readable description of the file. This is recommended to be the filename of the original upload.
|
||||
|
@ -27,7 +27,7 @@ data class MessageImageContent(
|
||||
/**
|
||||
* Required. Must be 'm.image'.
|
||||
*/
|
||||
@Json(name = "msgtype") override val msgType: String,
|
||||
@Json(name = MessageContent.MSG_TYPE_JSON_KEY) override val msgType: String,
|
||||
|
||||
/**
|
||||
* Required. A textual representation of the image. This could be the alt text of the image, the filename of the image,
|
||||
|
@ -26,7 +26,7 @@ data class MessageLocationContent(
|
||||
/**
|
||||
* Required. Must be 'm.location'.
|
||||
*/
|
||||
@Json(name = "msgtype") override val msgType: String,
|
||||
@Json(name = MessageContent.MSG_TYPE_JSON_KEY) override val msgType: String,
|
||||
|
||||
/**
|
||||
* Required. A description of the location e.g. 'Big Ben, London, UK', or some kind
|
||||
|
@ -26,7 +26,7 @@ data class MessageNoticeContent(
|
||||
/**
|
||||
* Required. Must be 'm.notice'.
|
||||
*/
|
||||
@Json(name = "msgtype") override val msgType: String,
|
||||
@Json(name = MessageContent.MSG_TYPE_JSON_KEY) override val msgType: String,
|
||||
|
||||
/**
|
||||
* Required. The notice text to send.
|
||||
|
@ -30,7 +30,7 @@ const val OPTION_TYPE_BUTTONS = "org.matrix.buttons"
|
||||
*/
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class MessageOptionsContent(
|
||||
@Json(name = "msgtype") override val msgType: String = MessageType.MSGTYPE_OPTIONS,
|
||||
@Json(name = MessageContent.MSG_TYPE_JSON_KEY) override val msgType: String = MessageType.MSGTYPE_OPTIONS,
|
||||
@Json(name = "type") val optionType: String? = null,
|
||||
@Json(name = "body") override val body: String,
|
||||
@Json(name = "label") val label: String?,
|
||||
|
@ -26,7 +26,7 @@ import org.matrix.android.sdk.api.session.room.model.relation.RelationDefaultCon
|
||||
*/
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class MessagePollResponseContent(
|
||||
@Json(name = "msgtype") override val msgType: String = MessageType.MSGTYPE_RESPONSE,
|
||||
@Json(name = MessageContent.MSG_TYPE_JSON_KEY) override val msgType: String = MessageType.MSGTYPE_RESPONSE,
|
||||
@Json(name = "body") override val body: String,
|
||||
@Json(name = "m.relates_to") override val relatesTo: RelationDefaultContent? = null,
|
||||
@Json(name = "m.new_content") override val newContent: Content? = null
|
||||
|
@ -26,7 +26,7 @@ data class MessageTextContent(
|
||||
/**
|
||||
* Required. Must be 'm.text'.
|
||||
*/
|
||||
@Json(name = "msgtype") override val msgType: String,
|
||||
@Json(name = MessageContent.MSG_TYPE_JSON_KEY) override val msgType: String,
|
||||
|
||||
/**
|
||||
* Required. The body of the message.
|
||||
|
@ -24,7 +24,7 @@ import org.matrix.android.sdk.internal.crypto.verification.VerificationInfoReque
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class MessageVerificationRequestContent(
|
||||
@Json(name = "msgtype") override val msgType: String = MessageType.MSGTYPE_VERIFICATION_REQUEST,
|
||||
@Json(name = MessageContent.MSG_TYPE_JSON_KEY)override val msgType: String = MessageType.MSGTYPE_VERIFICATION_REQUEST,
|
||||
@Json(name = "body") override val body: String,
|
||||
@Json(name = "from_device") override val fromDevice: String?,
|
||||
@Json(name = "methods") override val methods: List<String>,
|
||||
|
@ -27,7 +27,7 @@ data class MessageVideoContent(
|
||||
/**
|
||||
* Required. Must be 'm.video'.
|
||||
*/
|
||||
@Json(name = "msgtype") override val msgType: String,
|
||||
@Json(name = MessageContent.MSG_TYPE_JSON_KEY)override val msgType: String,
|
||||
|
||||
/**
|
||||
* Required. A description of the video e.g. 'Gangnam style', or some kind of content description for accessibility e.g. 'video attachment'.
|
||||
|
@ -94,5 +94,7 @@ interface SpaceService {
|
||||
*/
|
||||
suspend fun setSpaceParent(childRoomId: String, parentSpaceId: String, canonical: Boolean, viaServers: List<String>)
|
||||
|
||||
suspend fun removeSpaceParent(childRoomId: String, parentSpaceId: String)
|
||||
|
||||
fun getRootSpaceSummaries(): List<RoomSummary>
|
||||
}
|
||||
|
@ -170,7 +170,7 @@ internal class MXMegolmEncryption(
|
||||
val deviceIds = devicesInRoom.getUserDeviceIds(userId)
|
||||
for (deviceId in deviceIds!!) {
|
||||
val deviceInfo = devicesInRoom.getObject(userId, deviceId)
|
||||
if (deviceInfo != null && !cryptoStore.getSharedSessionInfo(roomId, safeSession.sessionId, userId, deviceId).found) {
|
||||
if (deviceInfo != null && !cryptoStore.getSharedSessionInfo(roomId, safeSession.sessionId, deviceInfo).found) {
|
||||
val devices = shareMap.getOrPut(userId) { ArrayList() }
|
||||
devices.add(deviceInfo)
|
||||
}
|
||||
@ -270,8 +270,8 @@ internal class MXMegolmEncryption(
|
||||
// for dead devices on every message.
|
||||
val gossipingEventBuffer = arrayListOf<Event>()
|
||||
for ((userId, devicesToShareWith) in devicesByUser) {
|
||||
for ((deviceId) in devicesToShareWith) {
|
||||
session.sharedWithHelper.markedSessionAsShared(userId, deviceId, chainIndex)
|
||||
for (deviceInfo in devicesToShareWith) {
|
||||
session.sharedWithHelper.markedSessionAsShared(deviceInfo, chainIndex)
|
||||
gossipingEventBuffer.add(
|
||||
Event(
|
||||
type = EventType.ROOM_KEY,
|
||||
@ -279,7 +279,7 @@ internal class MXMegolmEncryption(
|
||||
content = submap.apply {
|
||||
this["session_key"] = ""
|
||||
// we add a fake key for trail
|
||||
this["_dest"] = "$userId|$deviceId"
|
||||
this["_dest"] = "$userId|${deviceInfo.deviceId}"
|
||||
}
|
||||
))
|
||||
}
|
||||
@ -429,7 +429,7 @@ internal class MXMegolmEncryption(
|
||||
.also { Timber.w("## Crypto reshareKey: Device not found") }
|
||||
|
||||
// Get the chain index of the key we previously sent this device
|
||||
val wasSessionSharedWithUser = cryptoStore.getSharedSessionInfo(roomId, sessionId, userId, deviceId)
|
||||
val wasSessionSharedWithUser = cryptoStore.getSharedSessionInfo(roomId, sessionId, deviceInfo)
|
||||
if (!wasSessionSharedWithUser.found) {
|
||||
// This session was never shared with this user
|
||||
// Send a room key with held
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.crypto.algorithms.megolm
|
||||
|
||||
import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo
|
||||
import org.matrix.android.sdk.internal.crypto.model.MXUsersDevicesMap
|
||||
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
|
||||
|
||||
@ -28,7 +29,13 @@ internal class SharedWithHelper(
|
||||
return cryptoStore.getSharedWithInfo(roomId, sessionId)
|
||||
}
|
||||
|
||||
fun markedSessionAsShared(userId: String, deviceId: String, chainIndex: Int) {
|
||||
cryptoStore.markedSessionAsShared(roomId, sessionId, userId, deviceId, chainIndex)
|
||||
fun markedSessionAsShared(deviceInfo: CryptoDeviceInfo, chainIndex: Int) {
|
||||
cryptoStore.markedSessionAsShared(
|
||||
roomId = roomId,
|
||||
sessionId = sessionId,
|
||||
userId = deviceInfo.userId,
|
||||
deviceId = deviceInfo.deviceId,
|
||||
deviceIdentityKey = deviceInfo.identityKey() ?: "",
|
||||
chainIndex = chainIndex)
|
||||
}
|
||||
}
|
||||
|
@ -450,7 +450,8 @@ internal interface IMXCryptoStore {
|
||||
fun addWithHeldMegolmSession(withHeldContent: RoomKeyWithHeldContent)
|
||||
fun getWithHeldMegolmSession(roomId: String, sessionId: String): RoomKeyWithHeldContent?
|
||||
|
||||
fun markedSessionAsShared(roomId: String?, sessionId: String, userId: String, deviceId: String, chainIndex: Int)
|
||||
fun markedSessionAsShared(roomId: String?, sessionId: String, userId: String, deviceId: String,
|
||||
deviceIdentityKey: String, chainIndex: Int)
|
||||
|
||||
/**
|
||||
* Query for information on this session sharing history.
|
||||
@ -459,7 +460,7 @@ internal interface IMXCryptoStore {
|
||||
* in this case chainIndex is not nullindicates the ratchet position.
|
||||
* In found is false, chainIndex is null
|
||||
*/
|
||||
fun getSharedSessionInfo(roomId: String?, sessionId: String, userId: String, deviceId: String): SharedSessionResult
|
||||
fun getSharedSessionInfo(roomId: String?, sessionId: String, deviceInfo: CryptoDeviceInfo): SharedSessionResult
|
||||
data class SharedSessionResult(val found: Boolean, val chainIndex: Int?)
|
||||
|
||||
fun getSharedWithInfo(roomId: String?, sessionId: String): MXUsersDevicesMap<Int>
|
||||
|
@ -1681,7 +1681,12 @@ internal class RealmCryptoStore @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
override fun markedSessionAsShared(roomId: String?, sessionId: String, userId: String, deviceId: String, chainIndex: Int) {
|
||||
override fun markedSessionAsShared(roomId: String?,
|
||||
sessionId: String,
|
||||
userId: String,
|
||||
deviceId: String,
|
||||
deviceIdentityKey: String,
|
||||
chainIndex: Int) {
|
||||
doRealmTransaction(realmConfiguration) { realm ->
|
||||
SharedSessionEntity.create(
|
||||
realm = realm,
|
||||
@ -1689,14 +1694,22 @@ internal class RealmCryptoStore @Inject constructor(
|
||||
sessionId = sessionId,
|
||||
userId = userId,
|
||||
deviceId = deviceId,
|
||||
deviceIdentityKey = deviceIdentityKey,
|
||||
chainIndex = chainIndex
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getSharedSessionInfo(roomId: String?, sessionId: String, userId: String, deviceId: String): IMXCryptoStore.SharedSessionResult {
|
||||
override fun getSharedSessionInfo(roomId: String?, sessionId: String, deviceInfo: CryptoDeviceInfo): IMXCryptoStore.SharedSessionResult {
|
||||
return doWithRealm(realmConfiguration) { realm ->
|
||||
SharedSessionEntity.get(realm, roomId, sessionId, userId, deviceId)?.let {
|
||||
SharedSessionEntity.get(
|
||||
realm = realm,
|
||||
roomId = roomId,
|
||||
sessionId = sessionId,
|
||||
userId = deviceInfo.userId,
|
||||
deviceId = deviceInfo.deviceId,
|
||||
deviceIdentityKey = deviceInfo.identityKey()
|
||||
)?.let {
|
||||
IMXCryptoStore.SharedSessionResult(true, it.chainIndex)
|
||||
} ?: IMXCryptoStore.SharedSessionResult(false, null)
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ internal object RealmCryptoStoreMigration : RealmMigration {
|
||||
// 0, 1, 2: legacy Riot-Android
|
||||
// 3: migrate to RiotX schema
|
||||
// 4, 5, 6, 7, 8, 9: migrations from RiotX (which was previously 1, 2, 3, 4, 5, 6)
|
||||
const val CRYPTO_STORE_SCHEMA_VERSION = 13L
|
||||
const val CRYPTO_STORE_SCHEMA_VERSION = 14L
|
||||
|
||||
private fun RealmObjectSchema.addFieldIfNotExists(fieldName: String, fieldType: Class<*>): RealmObjectSchema {
|
||||
if (!hasField(fieldName)) {
|
||||
@ -94,6 +94,7 @@ internal object RealmCryptoStoreMigration : RealmMigration {
|
||||
if (oldVersion <= 10) migrateTo11(realm)
|
||||
if (oldVersion <= 11) migrateTo12(realm)
|
||||
if (oldVersion <= 12) migrateTo13(realm)
|
||||
if (oldVersion <= 13) migrateTo14(realm)
|
||||
}
|
||||
|
||||
private fun migrateTo1Legacy(realm: DynamicRealm) {
|
||||
@ -554,4 +555,21 @@ internal object RealmCryptoStoreMigration : RealmMigration {
|
||||
Timber.e("TrustLevelEntity cleanup: Something is not correct...")
|
||||
}
|
||||
}
|
||||
|
||||
// Version 14L Update the way we remember key sharing
|
||||
private fun migrateTo14(realm: DynamicRealm) {
|
||||
Timber.d("Step 13 -> 14")
|
||||
realm.schema.get("SharedSessionEntity")
|
||||
?.addField(SharedSessionEntityFields.DEVICE_IDENTITY_KEY, String::class.java)
|
||||
?.addIndex(SharedSessionEntityFields.DEVICE_IDENTITY_KEY)
|
||||
?.transform {
|
||||
val sharedUserId = it.getString(SharedSessionEntityFields.USER_ID)
|
||||
val sharedDeviceId = it.getString(SharedSessionEntityFields.DEVICE_ID)
|
||||
val knownDevice = realm.where("DeviceInfoEntity")
|
||||
.equalTo(DeviceInfoEntityFields.USER_ID, sharedUserId)
|
||||
.equalTo(DeviceInfoEntityFields.DEVICE_ID, sharedDeviceId)
|
||||
.findFirst()
|
||||
it.setString(SharedSessionEntityFields.DEVICE_IDENTITY_KEY, knownDevice?.getString(DeviceInfoEntityFields.IDENTITY_KEY))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ internal open class SharedSessionEntity(
|
||||
@Index var sessionId: String? = null,
|
||||
@Index var userId: String? = null,
|
||||
@Index var deviceId: String? = null,
|
||||
@Index var deviceIdentityKey: String? = null,
|
||||
var chainIndex: Int? = null
|
||||
) : RealmObject() {
|
||||
|
||||
|
@ -16,15 +16,20 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.crypto.store.db.query
|
||||
|
||||
import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.SharedSessionEntity
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.SharedSessionEntityFields
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmResults
|
||||
import io.realm.kotlin.createObject
|
||||
import io.realm.kotlin.where
|
||||
import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.SharedSessionEntity
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.SharedSessionEntityFields
|
||||
|
||||
internal fun SharedSessionEntity.Companion.get(realm: Realm, roomId: String?, sessionId: String, userId: String, deviceId: String)
|
||||
internal fun SharedSessionEntity.Companion.get(realm: Realm,
|
||||
roomId: String?,
|
||||
sessionId: String,
|
||||
userId: String,
|
||||
deviceId: String,
|
||||
deviceIdentityKey: String?)
|
||||
: SharedSessionEntity? {
|
||||
return realm.where<SharedSessionEntity>()
|
||||
.equalTo(SharedSessionEntityFields.ROOM_ID, roomId)
|
||||
@ -32,6 +37,7 @@ internal fun SharedSessionEntity.Companion.get(realm: Realm, roomId: String?, se
|
||||
.equalTo(SharedSessionEntityFields.ALGORITHM, MXCRYPTO_ALGORITHM_MEGOLM)
|
||||
.equalTo(SharedSessionEntityFields.USER_ID, userId)
|
||||
.equalTo(SharedSessionEntityFields.DEVICE_ID, deviceId)
|
||||
.equalTo(SharedSessionEntityFields.DEVICE_IDENTITY_KEY, deviceIdentityKey)
|
||||
.findFirst()
|
||||
}
|
||||
|
||||
@ -44,7 +50,12 @@ internal fun SharedSessionEntity.Companion.get(realm: Realm, roomId: String?, se
|
||||
.findAll()
|
||||
}
|
||||
|
||||
internal fun SharedSessionEntity.Companion.create(realm: Realm, roomId: String?, sessionId: String, userId: String, deviceId: String, chainIndex: Int)
|
||||
internal fun SharedSessionEntity.Companion.create(realm: Realm, roomId: String?,
|
||||
sessionId: String,
|
||||
userId: String,
|
||||
deviceId: String,
|
||||
deviceIdentityKey: String,
|
||||
chainIndex: Int)
|
||||
: SharedSessionEntity {
|
||||
return realm.createObject<SharedSessionEntity>().apply {
|
||||
this.roomId = roomId
|
||||
@ -52,6 +63,7 @@ internal fun SharedSessionEntity.Companion.create(realm: Realm, roomId: String?,
|
||||
this.sessionId = sessionId
|
||||
this.userId = userId
|
||||
this.deviceId = deviceId
|
||||
this.deviceIdentityKey = deviceIdentityKey
|
||||
this.chainIndex = chainIndex
|
||||
}
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ internal class UserAgentHolder @Inject constructor(private val context: Context,
|
||||
|
||||
/**
|
||||
* Create an user agent with the application version.
|
||||
* Ex: Element/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; MatrixAndroidSdk2 1.0)
|
||||
*
|
||||
* @param flavorDescription the flavor description
|
||||
*/
|
||||
@ -74,13 +74,13 @@ internal class UserAgentHolder @Inject constructor(private val context: Context,
|
||||
// if there is no user agent or cannot parse it
|
||||
if (null == systemUserAgent || systemUserAgent.lastIndexOf(")") == -1 || !systemUserAgent.contains("(")) {
|
||||
userAgent = (appName + "/" + appVersion + " ( Flavour " + flavorDescription
|
||||
+ "; MatrixAndroidSDK_X " + BuildConfig.VERSION_NAME + ")")
|
||||
+ "; MatrixAndroidSdk2 " + BuildConfig.SDK_VERSION + ")")
|
||||
} else {
|
||||
// update
|
||||
userAgent = appName + "/" + appVersion + " " +
|
||||
systemUserAgent.substring(systemUserAgent.indexOf("("), systemUserAgent.lastIndexOf(")") - 1) +
|
||||
"; Flavour " + flavorDescription +
|
||||
"; MatrixAndroidSDK_X " + BuildConfig.VERSION_NAME + ")"
|
||||
"; MatrixAndroidSdk2 " + BuildConfig.SDK_VERSION + ")"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.room.model.RoomStrippedState
|
||||
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 GetRoomSummaryTask : Task<GetRoomSummaryTask.Params, RoomStrippedState> {
|
||||
data class Params(
|
||||
val roomId: String,
|
||||
val viaServers: List<String>?
|
||||
)
|
||||
}
|
||||
|
||||
internal class DefaultGetRoomSummaryTask @Inject constructor(
|
||||
private val roomAPI: RoomAPI,
|
||||
private val globalErrorReceiver: GlobalErrorReceiver
|
||||
) : GetRoomSummaryTask {
|
||||
|
||||
override suspend fun execute(params: GetRoomSummaryTask.Params): RoomStrippedState {
|
||||
return executeRequest(globalErrorReceiver) {
|
||||
roomAPI.getRoomSummary(params.roomId, params.viaServers)
|
||||
}
|
||||
}
|
||||
}
|
@ -19,6 +19,7 @@ package org.matrix.android.sdk.internal.session.room
|
||||
import org.matrix.android.sdk.api.session.events.model.Content
|
||||
import org.matrix.android.sdk.api.session.events.model.Event
|
||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomStrippedState
|
||||
import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoomsParams
|
||||
import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoomsResponse
|
||||
import org.matrix.android.sdk.api.util.JsonDict
|
||||
@ -254,7 +255,7 @@ internal interface RoomAPI {
|
||||
@POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "join/{roomIdOrAlias}")
|
||||
suspend fun join(@Path("roomIdOrAlias") roomIdOrAlias: String,
|
||||
@Query("server_name") viaServers: List<String>,
|
||||
@Body params: JsonDict): JoinRoomResponse
|
||||
@Body params: JsonDict): JoinRoomResponse
|
||||
|
||||
/**
|
||||
* Leave the given room.
|
||||
@ -381,4 +382,14 @@ internal interface RoomAPI {
|
||||
@POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/upgrade")
|
||||
suspend fun upgradeRoom(@Path("roomId") roomId: String,
|
||||
@Body body: RoomUpgradeBody): RoomUpgradeResponse
|
||||
|
||||
/**
|
||||
* The API returns the summary of the specified room, if the room could be found and the client should be able to view
|
||||
* its contents according to the join_rules, history visibility, space membership and similar rules outlined in MSC3173
|
||||
* as well as if the user is already a member of that room.
|
||||
* https://github.com/deepbluev7/matrix-doc/blob/room-summaries/proposals/3266-room-summary.md
|
||||
*/
|
||||
@GET(NetworkConstants.URI_API_PREFIX_PATH_UNSTABLE + "im.nheko.summary/rooms/{roomIdOrAlias}/summary")
|
||||
suspend fun getRoomSummary(@Path("roomIdOrAlias") roomidOrAlias: String,
|
||||
@Query("via") viaServers: List<String>?): RoomStrippedState
|
||||
}
|
||||
|
@ -253,4 +253,7 @@ internal abstract class RoomModule {
|
||||
|
||||
@Binds
|
||||
abstract fun bindSign3pidInvitationTask(task: DefaultSign3pidInvitationTask): Sign3pidInvitationTask
|
||||
|
||||
@Binds
|
||||
abstract fun bindGetRoomSummaryTask(task: DefaultGetRoomSummaryTask): GetRoomSummaryTask
|
||||
}
|
||||
|
@ -33,6 +33,7 @@ import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoomsFi
|
||||
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.GetRoomSummaryTask
|
||||
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
|
||||
@ -49,6 +50,7 @@ internal class DefaultPeekRoomTask @Inject constructor(
|
||||
private val getRoomIdByAliasTask: GetRoomIdByAliasTask,
|
||||
private val getRoomDirectoryVisibilityTask: GetRoomDirectoryVisibilityTask,
|
||||
private val getPublicRoomTask: GetPublicRoomTask,
|
||||
private val getRoomSummaryTask: GetRoomSummaryTask,
|
||||
private val resolveRoomStateTask: ResolveRoomStateTask
|
||||
) : PeekRoomTask {
|
||||
|
||||
@ -70,6 +72,25 @@ internal class DefaultPeekRoomTask @Inject constructor(
|
||||
serverList = emptyList()
|
||||
}
|
||||
|
||||
// If the room summary API is available on the Home Server we should try it first
|
||||
val strippedState = tryOrNull("Failed to get room stripped state roomId:$roomId") {
|
||||
getRoomSummaryTask.execute(GetRoomSummaryTask.Params(roomId, serverList))
|
||||
}
|
||||
if (strippedState != null) {
|
||||
return PeekResult.Success(
|
||||
roomId = strippedState.roomId,
|
||||
alias = strippedState.getPrimaryAlias() ?: params.roomIdOrAlias.takeIf { isAlias },
|
||||
avatarUrl = strippedState.avatarUrl,
|
||||
name = strippedState.name,
|
||||
topic = strippedState.topic,
|
||||
numJoinedMembers = strippedState.numJoinedMembers,
|
||||
viaServers = serverList,
|
||||
roomType = strippedState.roomType,
|
||||
someMembers = null,
|
||||
isPublic = strippedState.worldReadable
|
||||
)
|
||||
}
|
||||
|
||||
// Is it a public room?
|
||||
val visibilityRes = tryOrNull("## PEEK: failed to get visibility") {
|
||||
getRoomDirectoryVisibilityTask.execute(GetRoomDirectoryVisibilityTask.Params(roomId))
|
||||
|
@ -23,6 +23,7 @@ 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.accountdata.RoomAccountDataTypes
|
||||
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.RoomAliasesContent
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomCanonicalAliasContent
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesContent
|
||||
@ -31,6 +32,7 @@ import org.matrix.android.sdk.api.session.room.model.RoomTopicContent
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomType
|
||||
import org.matrix.android.sdk.api.session.room.model.VersioningState
|
||||
import org.matrix.android.sdk.api.session.room.model.create.RoomCreateContent
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
|
||||
import org.matrix.android.sdk.api.session.room.send.SendState
|
||||
import org.matrix.android.sdk.internal.crypto.EventDecryptor
|
||||
import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM
|
||||
@ -207,63 +209,102 @@ internal class RoomSummaryUpdater @Inject constructor(
|
||||
}
|
||||
.toMap()
|
||||
|
||||
lookupMap.keys.forEach { lookedUp ->
|
||||
if (lookedUp.roomType == RoomType.SPACE) {
|
||||
// get childrens
|
||||
// First handle child relations
|
||||
lookupMap.keys.asSequence()
|
||||
.filter { it.roomType == RoomType.SPACE }
|
||||
.forEach { lookedUp ->
|
||||
// get childrens
|
||||
|
||||
lookedUp.children.clearWith { it.deleteFromRealm() }
|
||||
lookedUp.children.clearWith { it.deleteFromRealm() }
|
||||
|
||||
RoomChildRelationInfo(realm, lookedUp.roomId).getDirectChildrenDescriptions().forEach { child ->
|
||||
RoomChildRelationInfo(realm, lookedUp.roomId).getDirectChildrenDescriptions().forEach { child ->
|
||||
|
||||
lookedUp.children.add(
|
||||
realm.createObject<SpaceChildSummaryEntity>().apply {
|
||||
this.childRoomId = child.roomId
|
||||
this.childSummaryEntity = RoomSummaryEntity.where(realm, child.roomId).findFirst()
|
||||
this.order = child.order
|
||||
lookedUp.children.add(
|
||||
realm.createObject<SpaceChildSummaryEntity>().apply {
|
||||
this.childRoomId = child.roomId
|
||||
this.childSummaryEntity = RoomSummaryEntity.where(realm, child.roomId).findFirst()
|
||||
this.order = child.order
|
||||
// this.autoJoin = child.autoJoin
|
||||
this.viaServers.addAll(child.viaServers)
|
||||
}
|
||||
)
|
||||
this.viaServers.addAll(child.viaServers)
|
||||
}
|
||||
)
|
||||
|
||||
RoomSummaryEntity.where(realm, child.roomId)
|
||||
.process(RoomSummaryEntityFields.MEMBERSHIP_STR, Membership.activeMemberships())
|
||||
.findFirst()
|
||||
?.let { childSum ->
|
||||
lookupMap.entries.firstOrNull { it.key.roomId == lookedUp.roomId }?.let { entry ->
|
||||
if (entry.value.indexOfFirst { it.roomId == childSum.roomId } == -1) {
|
||||
// add looked up as a parent
|
||||
entry.value.add(childSum)
|
||||
RoomSummaryEntity.where(realm, child.roomId)
|
||||
.process(RoomSummaryEntityFields.MEMBERSHIP_STR, Membership.activeMemberships())
|
||||
.findFirst()
|
||||
?.let { childSum ->
|
||||
lookupMap.entries.firstOrNull { it.key.roomId == lookedUp.roomId }?.let { entry ->
|
||||
if (entry.value.indexOfFirst { it.roomId == childSum.roomId } == -1) {
|
||||
// add looked up as a parent
|
||||
entry.value.add(childSum)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now let's check parent relations
|
||||
|
||||
lookupMap.keys
|
||||
.forEach { lookedUp ->
|
||||
lookedUp.parents.clearWith { it.deleteFromRealm() }
|
||||
// can we check parent relations here??
|
||||
/**
|
||||
* rooms can claim parents via the m.space.parent state event.
|
||||
* canonical determines whether this is the main parent for the space.
|
||||
*
|
||||
* To avoid abuse where a room admin falsely claims that a room is part of a space that it should not be,
|
||||
* clients could ignore such m.space.parent events unless either
|
||||
* (a) there is a corresponding m.space.child event in the claimed parent, or
|
||||
* (b) the sender of the m.space.child event has a sufficient power-level to send such an m.space.child event in the parent.
|
||||
* (It is not necessarily required that that user currently be a member of the parent room -
|
||||
* only the m.room.power_levels event is inspected.)
|
||||
* [Checking the power-level rather than requiring an actual m.space.child event in the parent allows for "secret" rooms (see below).]
|
||||
*/
|
||||
RoomChildRelationInfo(realm, lookedUp.roomId).getParentDescriptions()
|
||||
.map { parentInfo ->
|
||||
// Is it a valid parent relation?
|
||||
// Check if it's a child of the parent?
|
||||
val isValidRelation: Boolean
|
||||
val parent = lookupMap.firstNotNullOfOrNull { if (it.key.roomId == parentInfo.roomId) it.value else null }
|
||||
if (parent?.firstOrNull { it.roomId == lookedUp.roomId } != null) {
|
||||
// there is a corresponding m.space.child event in the claimed parent
|
||||
isValidRelation = true
|
||||
} else {
|
||||
// check if sender can post child relation in parent?
|
||||
val senderId = parentInfo.stateEventSender
|
||||
val parentRoomId = parentInfo.roomId
|
||||
val powerLevelsHelper = CurrentStateEventEntity
|
||||
.getOrNull(realm, parentRoomId, "", EventType.STATE_ROOM_POWER_LEVELS)
|
||||
?.root
|
||||
?.let { ContentMapper.map(it.content).toModel<PowerLevelsContent>() }
|
||||
?.let { PowerLevelsHelper(it) }
|
||||
|
||||
isValidRelation = powerLevelsHelper?.isUserAllowedToSend(senderId, true, EventType.STATE_SPACE_CHILD) ?: false
|
||||
}
|
||||
|
||||
if (isValidRelation) {
|
||||
lookedUp.parents.add(
|
||||
realm.createObject<SpaceParentSummaryEntity>().apply {
|
||||
this.parentRoomId = parentInfo.roomId
|
||||
this.parentSummaryEntity = RoomSummaryEntity.where(realm, parentInfo.roomId).findFirst()
|
||||
this.canonical = parentInfo.canonical
|
||||
this.viaServers.addAll(parentInfo.viaServers)
|
||||
}
|
||||
)
|
||||
|
||||
RoomSummaryEntity.where(realm, parentInfo.roomId)
|
||||
.process(RoomSummaryEntityFields.MEMBERSHIP_STR, Membership.activeMemberships())
|
||||
.findFirst()
|
||||
?.let { parentSum ->
|
||||
if (lookupMap[parentSum]?.indexOfFirst { it.roomId == lookedUp.roomId } == -1) {
|
||||
// add lookedup as a parent
|
||||
lookupMap[parentSum]?.add(lookedUp)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
lookedUp.parents.clearWith { it.deleteFromRealm() }
|
||||
// can we check parent relations here??
|
||||
RoomChildRelationInfo(realm, lookedUp.roomId).getParentDescriptions()
|
||||
.map { parentInfo ->
|
||||
|
||||
lookedUp.parents.add(
|
||||
realm.createObject<SpaceParentSummaryEntity>().apply {
|
||||
this.parentRoomId = parentInfo.roomId
|
||||
this.parentSummaryEntity = RoomSummaryEntity.where(realm, parentInfo.roomId).findFirst()
|
||||
this.canonical = parentInfo.canonical
|
||||
this.viaServers.addAll(parentInfo.viaServers)
|
||||
}
|
||||
)
|
||||
|
||||
RoomSummaryEntity.where(realm, parentInfo.roomId)
|
||||
.process(RoomSummaryEntityFields.MEMBERSHIP_STR, Membership.activeMemberships())
|
||||
.findFirst()
|
||||
?.let { parentSum ->
|
||||
if (lookupMap[parentSum]?.indexOfFirst { it.roomId == lookedUp.roomId } == -1) {
|
||||
// add lookedup as a parent
|
||||
lookupMap[parentSum]?.add(lookedUp)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Simple algorithm to break cycles
|
||||
// Need more work to decide how to break, probably need to be as consistent as possible
|
||||
|
@ -89,7 +89,6 @@ internal class DefaultSpace(
|
||||
body = SpaceChildContent(
|
||||
order = null,
|
||||
via = null,
|
||||
// autoJoin = null,
|
||||
suggested = null
|
||||
).toContent()
|
||||
)
|
||||
|
@ -33,6 +33,7 @@ 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.create.CreateRoomPreset
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.Role
|
||||
import org.matrix.android.sdk.api.session.space.CreateSpaceParams
|
||||
import org.matrix.android.sdk.api.session.space.JoinSpaceResult
|
||||
import org.matrix.android.sdk.api.session.space.Space
|
||||
@ -77,7 +78,7 @@ internal class DefaultSpaceService @Inject constructor(
|
||||
if (isPublic) {
|
||||
this.roomAliasName = roomAliasLocalPart
|
||||
this.powerLevelContentOverride = (powerLevelContentOverride ?: PowerLevelsContent()).copy(
|
||||
invite = 0
|
||||
invite = if (isPublic) Role.Default.value else Role.Moderator.value
|
||||
)
|
||||
this.preset = CreateRoomPreset.PRESET_PUBLIC_CHAT
|
||||
this.historyVisibility = RoomHistoryVisibility.WORLD_READABLE
|
||||
@ -221,4 +222,23 @@ internal class DefaultSpaceService @Inject constructor(
|
||||
).toContent()
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun removeSpaceParent(childRoomId: String, parentSpaceId: String) {
|
||||
val room = roomGetter.getRoom(childRoomId)
|
||||
?: throw IllegalArgumentException("Unknown Room $childRoomId")
|
||||
|
||||
val existingEvent = room.getStateEvent(EventType.STATE_SPACE_PARENT, QueryStringValue.Equals(parentSpaceId))
|
||||
if (existingEvent != null) {
|
||||
// Should i check if it was sent by me?
|
||||
// we don't check power level, it will throw if you cannot do that
|
||||
room.sendStateEvent(
|
||||
eventType = EventType.STATE_SPACE_PARENT,
|
||||
stateKey = parentSpaceId,
|
||||
body = SpaceParentContent(
|
||||
via = null,
|
||||
canonical = null
|
||||
).toContent()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,14 +19,11 @@ apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-parcelize'
|
||||
|
||||
android {
|
||||
compileSdkVersion 30
|
||||
compileSdk versions.compileSdk
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 19
|
||||
targetSdkVersion 30
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
|
||||
minSdk versions.minSdk
|
||||
targetSdk versions.targetSdk
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
consumerProguardFiles 'consumer-rules.pro'
|
||||
}
|
||||
@ -41,11 +38,11 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
implementation 'androidx.appcompat:appcompat:1.3.1'
|
||||
implementation "androidx.fragment:fragment-ktx:1.3.6"
|
||||
implementation 'androidx.exifinterface:exifinterface:1.3.3'
|
||||
implementation libs.jetbrains.kotlinStdlibJdk7
|
||||
implementation libs.androidx.appCompat
|
||||
implementation libs.androidx.fragmentKtx
|
||||
implementation libs.androidx.exifinterface
|
||||
|
||||
// Log
|
||||
implementation 'com.jakewharton.timber:timber:5.0.1'
|
||||
implementation libs.jakewharton.timber
|
||||
}
|
||||
|
@ -162,7 +162,7 @@ Formatter\.formatShortFileSize===1
|
||||
# android\.text\.TextUtils
|
||||
|
||||
### This is not a rule, but a warning: the number of "enum class" has changed. For Json classes, it is mandatory that they have `@JsonClass(generateAdapter = false)`. If the enum is not used as a Json class, change the value in file forbidden_strings_in_code.txt
|
||||
enum class===105
|
||||
enum class===106
|
||||
|
||||
### Do not import temporary legacy classes
|
||||
import org.matrix.android.sdk.internal.legacy.riot===3
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user