mirror of
https://github.com/element-hq/element-android
synced 2024-11-24 02:15:35 +03:00
Merge branch 'develop' into feature/aris/threads
# Conflicts: # .github/workflows/integration.yml # matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt # vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt # vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerViewState.kt
This commit is contained in:
commit
9d48ecea2f
150 changed files with 916 additions and 320 deletions
90
.github/workflows/integration.yml
vendored
90
.github/workflows/integration.yml
vendored
|
@ -1,90 +0,0 @@
|
|||
name: Integration Test
|
||||
|
||||
on:
|
||||
pull_request: { }
|
||||
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
|
||||
compile-android-test:
|
||||
name: Compile Android tests
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
~/.gradle/caches
|
||||
~/.gradle/wrapper
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gradle-
|
||||
- name: Compile Android tests
|
||||
run: ./gradlew clean assembleAndroidTest $CI_GRADLE_ARG_PROPERTIES --stacktrace -PallWarningsAsErrors=false
|
||||
|
||||
integration-tests:
|
||||
name: Integration Tests (Synapse)
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
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:
|
||||
python-version: 3.8
|
||||
- name: Cache pip
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pip-
|
||||
${{ runner.os }}-
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
~/.gradle/caches
|
||||
~/.gradle/wrapper
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gradle-
|
||||
- name: Start synapse server
|
||||
run: |
|
||||
python3 -m venv .synapse
|
||||
source .synapse/bin/activate
|
||||
pip install synapse matrix-synapse
|
||||
curl https://raw.githubusercontent.com/matrix-org/synapse/develop/demo/start.sh -o start.sh
|
||||
chmod 777 start.sh
|
||||
./start.sh --no-rate-limit
|
||||
- name: Run integration tests on API ${{ matrix.api-level }}
|
||||
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
|
||||
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
|
||||
script: ./gradlew $CI_GRADLE_ARG_PROPERTIES -Pandroid.testInstrumentationRunnerArguments.class=org.matrix.android.sdk.session.room.threads.ThreadMessagingTest matrix-sdk-android:connectedAndroidTest --info
|
||||
|
||||
|
208
.github/workflows/integration_tests.yml
vendored
Normal file
208
.github/workflows/integration_tests.yml
vendored
Normal file
|
@ -0,0 +1,208 @@
|
|||
name: Integration Tests
|
||||
|
||||
on:
|
||||
pull_request: { }
|
||||
push:
|
||||
branches: [ main, develop ]
|
||||
|
||||
# Enrich gradle.properties for CI/CD
|
||||
env:
|
||||
CI_GRADLE_ARG_PROPERTIES: >
|
||||
-Porg.gradle.jvmargs=-Xmx2g
|
||||
-Porg.gradle.parallel=false
|
||||
|
||||
jobs:
|
||||
# Build Android Tests [Matrix SDK]
|
||||
build-android-test-matrix-sdk:
|
||||
name: Matrix SDK - Build Android Tests
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
~/.gradle/caches
|
||||
~/.gradle/wrapper
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gradle-
|
||||
- name: Build Android Tests for matrix-sdk-android
|
||||
run: ./gradlew clean matrix-sdk-android:assembleAndroidTest $CI_GRADLE_ARG_PROPERTIES --stacktrace -PallWarningsAsErrors=false
|
||||
|
||||
# Build Android Tests [Matrix APP]
|
||||
build-android-test-app:
|
||||
name: App - Build Android Tests
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
~/.gradle/caches
|
||||
~/.gradle/wrapper
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gradle-
|
||||
- name: Build Android Tests for vector
|
||||
run: ./gradlew clean vector:assembleAndroidTest $CI_GRADLE_ARG_PROPERTIES --stacktrace -PallWarningsAsErrors=false
|
||||
|
||||
# Run Android Tests
|
||||
integration-tests:
|
||||
name: Matrix SDK - Running Integration Tests
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
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:
|
||||
python-version: 3.8
|
||||
- name: Cache pip
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pip-
|
||||
${{ runner.os }}-
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
~/.gradle/caches
|
||||
~/.gradle/wrapper
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gradle-
|
||||
- name: Start synapse server
|
||||
run: |
|
||||
python3 -m venv .synapse
|
||||
source .synapse/bin/activate
|
||||
pip install synapse matrix-synapse
|
||||
curl https://raw.githubusercontent.com/matrix-org/synapse/develop/demo/start.sh -o start.sh
|
||||
chmod 777 start.sh
|
||||
./start.sh --no-rate-limit
|
||||
# package: org.matrix.android.sdk.session
|
||||
- name: Run integration tests for Matrix SDK [org.matrix.android.sdk.session] API[${{ matrix.api-level }}]
|
||||
continue-on-error: true
|
||||
uses: reactivecircus/android-emulator-runner@v2
|
||||
with:
|
||||
api-level: ${{ matrix.api-level }}
|
||||
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 -Pandroid.testInstrumentationRunnerArguments.package='org.matrix.android.sdk.session' matrix-sdk-android:connectedDebugAndroidTest
|
||||
- name: Read Results [org.matrix.android.sdk.session]
|
||||
continue-on-error: true
|
||||
id: get-comment-body-session
|
||||
run: |
|
||||
body="$(cat ./matrix-sdk-android/build/outputs/androidTest-results/connected/*.xml | grep "<testsuite" | sed "s@.*tests=\(.*\)time=.*@\1@")"
|
||||
echo "::set-output name=session::passed=$body"
|
||||
# package: org.matrix.android.sdk.account
|
||||
- name: Run integration tests for Matrix SDK [org.matrix.android.sdk.account] API[${{ matrix.api-level }}]
|
||||
continue-on-error: true
|
||||
uses: reactivecircus/android-emulator-runner@v2
|
||||
with:
|
||||
api-level: ${{ matrix.api-level }}
|
||||
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 -Pandroid.testInstrumentationRunnerArguments.package='org.matrix.android.sdk.account' matrix-sdk-android:connectedDebugAndroidTest
|
||||
- name: Read Results [org.matrix.android.sdk.account]
|
||||
continue-on-error: true
|
||||
id: get-comment-body-account
|
||||
run: |
|
||||
body="$(cat ./matrix-sdk-android/build/outputs/androidTest-results/connected/*.xml | grep "<testsuite" | sed "s@.*tests=\(.*\)time=.*@\1@")"
|
||||
echo "::set-output name=account::passed=$body"
|
||||
# package: org.matrix.android.sdk.internal
|
||||
- name: Run integration tests for Matrix SDK [org.matrix.android.sdk.internal] API[${{ matrix.api-level }}]
|
||||
continue-on-error: true
|
||||
uses: reactivecircus/android-emulator-runner@v2
|
||||
with:
|
||||
api-level: ${{ matrix.api-level }}
|
||||
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 -Pandroid.testInstrumentationRunnerArguments.package='org.matrix.android.sdk.internal' matrix-sdk-android:connectedDebugAndroidTest
|
||||
- name: Read Results [org.matrix.android.sdk.internal]
|
||||
continue-on-error: true
|
||||
id: get-comment-body-internal
|
||||
run: |
|
||||
body="$(cat ./matrix-sdk-android/build/outputs/androidTest-results/connected/*.xml | grep "<testsuite" | sed "s@.*tests=\(.*\)time=.*@\1@")"
|
||||
echo "::set-output name=internal::passed=$body"
|
||||
# package: org.matrix.android.sdk.ordering
|
||||
- name: Run integration tests for Matrix SDK [org.matrix.android.sdk.ordering] API[${{ matrix.api-level }}]
|
||||
continue-on-error: true
|
||||
uses: reactivecircus/android-emulator-runner@v2
|
||||
with:
|
||||
api-level: ${{ matrix.api-level }}
|
||||
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 -Pandroid.testInstrumentationRunnerArguments.package='org.matrix.android.sdk.ordering' matrix-sdk-android:connectedDebugAndroidTest
|
||||
- name: Read Results [org.matrix.android.sdk.ordering]
|
||||
continue-on-error: true
|
||||
id: get-comment-body-ordering
|
||||
run: |
|
||||
body="$(cat ./matrix-sdk-android/build/outputs/androidTest-results/connected/*.xml | grep "<testsuite" | sed "s@.*tests=\(.*\)time=.*@\1@")"
|
||||
echo "::set-output name=ordering::passed=$body"
|
||||
# package: class PermalinkParserTest
|
||||
- name: Run integration tests for Matrix SDK class [org.matrix.android.sdk.PermalinkParserTest] API[${{ matrix.api-level }}]
|
||||
continue-on-error: true
|
||||
uses: reactivecircus/android-emulator-runner@v2
|
||||
with:
|
||||
api-level: ${{ matrix.api-level }}
|
||||
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 -Pandroid.testInstrumentationRunnerArguments.class='org.matrix.android.sdk.PermalinkParserTest' matrix-sdk-android:connectedDebugAndroidTest
|
||||
- name: Read Results [org.matrix.android.sd.PermalinkParserTest]
|
||||
continue-on-error: true
|
||||
id: get-comment-body-permalink
|
||||
run: |
|
||||
body="$(cat ./matrix-sdk-android/build/outputs/androidTest-results/connected/*.xml | grep "<testsuite" | sed "s@.*tests=\(.*\)time=.*@\1@")"
|
||||
echo "::set-output name=permalink::passed=$body"
|
||||
- name: Find Comment
|
||||
uses: peter-evans/find-comment@v1
|
||||
id: fc
|
||||
with:
|
||||
issue-number: ${{ github.event.pull_request.number }}
|
||||
comment-author: 'github-actions[bot]'
|
||||
body-includes: Integration Tests Results
|
||||
- name: Publish results to PR
|
||||
uses: peter-evans/create-or-update-comment@v1
|
||||
with:
|
||||
comment-id: ${{ steps.fc.outputs.comment-id }}
|
||||
issue-number: ${{ github.event.pull_request.number }}
|
||||
body: |
|
||||
### Matrix SDK
|
||||
## Integration Tests Results:
|
||||
- `[org.matrix.android.sdk.session]`<br>${{ steps.get-comment-body-session.outputs.session }}
|
||||
- `[org.matrix.android.sdk.account]`<br>${{ steps.get-comment-body-account.outputs.account }}
|
||||
- `[org.matrix.android.sdk.internal]`<br>${{ steps.get-comment-body-internal.outputs.internal }}
|
||||
- `[org.matrix.android.sdk.ordering]`<br>${{ steps.get-comment-body-ordering.outputs.ordering }}
|
||||
- `[org.matrix.android.sdk.PermalinkParserTest]`<br>${{ steps.get-comment-body-permalink.outputs.permalink }}
|
||||
edit-mode: replace
|
||||
## Useful commands
|
||||
# script: ./integration_tests_script.sh
|
||||
# script: ./gradlew $CI_GRADLE_ARG_PROPERTIES -Pandroid.testInstrumentationRunnerArguments.package='org.matrix.android.sdk.session' matrix-sdk-android:connectedDebugAndroidTest --info
|
||||
# script: ./gradlew $CI_GRADLE_ARG_PROPERTIES matrix-sdk-android:connectedAndroidTest --info
|
||||
# script: ./gradlew $CI_GRADLE_ARG_PROPERTIES -PallWarningsAsErrors=false connectedCheck --stacktrace
|
||||
# script: ./gradlew $CI_GRADLE_ARG_PROPERTIES -Pandroid.testInstrumentationRunnerArguments.class=org.matrix.android.sdk.session.room.timeline.ChunkEntityTest matrix-sdk-android:connectedAndroidTest --info
|
53
CHANGES.md
53
CHANGES.md
|
@ -1,3 +1,56 @@
|
|||
Changes in Element v1.3.14 (2022-01-12)
|
||||
=======================================
|
||||
|
||||
Bugfixes 🐛
|
||||
----------
|
||||
- Fix sending events in encrypted rooms broken, and incremental sync broken in 1.3.13 ([#4924](https://github.com/vector-im/element-android/issues/4924))
|
||||
|
||||
|
||||
Changes in Element v1.3.13 (2022-01-11)
|
||||
=======================================
|
||||
|
||||
Features ✨
|
||||
----------
|
||||
- Updates onboarding splash screen to have a dedicated sign in button and removes the dual purpose sign in/up stage ([#4382](https://github.com/vector-im/element-android/issues/4382))
|
||||
- Display Analytics opt-in screen at first start-up of the app ([#4892](https://github.com/vector-im/element-android/issues/4892))
|
||||
- New attachment picker UI ([#3444](https://github.com/vector-im/element-android/issues/3444))
|
||||
- Add labs support for rendering LaTeX maths (MSC2191) ([#2133](https://github.com/vector-im/element-android/issues/2133))
|
||||
- Allow changing nick colors from the member detail screen ([#2614](https://github.com/vector-im/element-android/issues/2614))
|
||||
- Analytics: Track Errors ([#4719](https://github.com/vector-im/element-android/issues/4719))
|
||||
- Change internal timeline management. ([#4405](https://github.com/vector-im/element-android/issues/4405))
|
||||
- Translate the error observed when the user is not allowed to join a room ([#4847](https://github.com/vector-im/element-android/issues/4847))
|
||||
|
||||
Bugfixes 🐛
|
||||
----------
|
||||
- Stop using CharSequence as EpoxyAttribute because it can lead to crash if the CharSequence mutates during rendering. ([#4837](https://github.com/vector-im/element-android/issues/4837))
|
||||
- Better handling of misconfigured room encryption ([#4711](https://github.com/vector-im/element-android/issues/4711))
|
||||
- Fix message replies/quotes to respect newlines. ([#4540](https://github.com/vector-im/element-android/issues/4540))
|
||||
- Polls: unable to create a poll with more than 10 answers ([#4735](https://github.com/vector-im/element-android/issues/4735))
|
||||
- Fix for broken unread message indicator on the room list when there are no messages in the room. ([#4749](https://github.com/vector-im/element-android/issues/4749))
|
||||
- Fixes newer emojis rendering strangely when inserting from the system keyboard ([#4756](https://github.com/vector-im/element-android/issues/4756))
|
||||
- Fixing unable to change change avatar in some scenarios ([#4767](https://github.com/vector-im/element-android/issues/4767))
|
||||
- Tentative fix for the speaker being used instead of earpiece for the outgoing call ringtone on lineage os ([#4781](https://github.com/vector-im/element-android/issues/4781))
|
||||
- Fixing crashes when quickly scrolling or restoring the room timeline ([#4789](https://github.com/vector-im/element-android/issues/4789))
|
||||
- Fixing encrypted non message events showing up as notification messages (eg when a participant joins, mutes or leaves a voice call) ([#4804](https://github.com/vector-im/element-android/issues/4804))
|
||||
|
||||
SDK API changes ⚠️
|
||||
------------------
|
||||
- Introduce method onStateUpdated on Timeline.Callback ([#4405](https://github.com/vector-im/element-android/issues/4405))
|
||||
- Support tagged events in Room Account Data (MSC2437) ([#4753](https://github.com/vector-im/element-android/issues/4753))
|
||||
|
||||
Other changes
|
||||
-------------
|
||||
- Workaround to fetch all the pending toDevice events from a Synapse homeserver ([#4612](https://github.com/vector-im/element-android/issues/4612))
|
||||
- Toolbar is added to a views with QR code scan ([#4644](https://github.com/vector-im/element-android/issues/4644))
|
||||
- Open share UI provides by the system when sharing media or text. ([#4745](https://github.com/vector-im/element-android/issues/4745))
|
||||
- Cleaning rendering of state events in timeline ([#4747](https://github.com/vector-im/element-android/issues/4747))
|
||||
- Enabling new FTUE Auth onboarding base, includes the "I already have an account" button in the splash ([#4872](https://github.com/vector-im/element-android/issues/4872))
|
||||
- Olm lib is now hosted in MavenCentral - upgrade to 3.2.10 ([#4882](https://github.com/vector-im/element-android/issues/4882))
|
||||
- Remove deprecated experimental restricted space lab option ([#4889](https://github.com/vector-im/element-android/issues/4889))
|
||||
- Add ktlint results on github as a comment only on fail ([#4888](https://github.com/vector-im/element-android/issues/4888))
|
||||
- Fix github actions ktlint reports and publish results on PR as comment ([#4864](https://github.com/vector-im/element-android/issues/4864))
|
||||
|
||||
|
||||
Changes in Element v1.3.12 (2021-12-20)
|
||||
=======================================
|
||||
|
||||
|
|
|
@ -139,7 +139,7 @@ If a string is not used anymore, it should be removed from the resource, but ple
|
|||
|
||||
Instead, please comment the original string with:
|
||||
```xml
|
||||
<!-- TO BE REMOVED -->
|
||||
<!-- TODO TO BE REMOVED -->
|
||||
```
|
||||
The string will be removed during the next sync with Weblate.
|
||||
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
Add labs support for rendering LaTeX maths (MSC2191)
|
|
@ -1 +0,0 @@
|
|||
Allow changing nick colors from the member detail screen
|
|
@ -1 +0,0 @@
|
|||
New attachment picker UI
|
|
@ -1 +0,0 @@
|
|||
Updates onboarding splash screen to have a dedicated sign in button and removes the dual purpose sign in/up stage
|
|
@ -1 +0,0 @@
|
|||
Change internal timeline management.
|
|
@ -1 +0,0 @@
|
|||
Introduce method onStateUpdated on Timeline.Callback
|
|
@ -1 +0,0 @@
|
|||
Fix message replies/quotes to respect newlines.
|
|
@ -1 +0,0 @@
|
|||
Workaround to fetch all the pending toDevice events from a Synapse homeserver
|
|
@ -1 +0,0 @@
|
|||
Toolbar is added to a views with QR code scan
|
|
@ -1 +0,0 @@
|
|||
Analytics: Track Errors
|
|
@ -1 +0,0 @@
|
|||
Polls: unable to create a poll with more than 10 answers
|
|
@ -1 +0,0 @@
|
|||
Open share UI provides by the system when sharing media or text.
|
|
@ -1 +0,0 @@
|
|||
Cleaning rendering of state events in timeline
|
|
@ -1 +0,0 @@
|
|||
Fix for broken unread message indicator on the room list when there are no messages in the room.
|
|
@ -1 +0,0 @@
|
|||
Support tagged events in Room Account Data (MSC2437)
|
|
@ -1 +0,0 @@
|
|||
Fixes newer emojis rendering strangely when inserting from the system keyboard
|
|
@ -1 +0,0 @@
|
|||
Fixing unable to change change avatar in some scenarios
|
|
@ -1 +0,0 @@
|
|||
Tentative fix for the speaker being used instead of earpiece for the outgoing call ringtone on lineage os
|
|
@ -1 +0,0 @@
|
|||
Fixing crashes when quickly scrolling or restoring the room timeline
|
|
@ -1 +0,0 @@
|
|||
Fixing encrypted non message events showing up as notification messages (eg when a participant joins, mutes or leaves a voice call)
|
|
@ -1 +0,0 @@
|
|||
Stop using CharSequence as EpoxyAttribute because it can lead to crash if the CharSequence mutates during rendering.
|
1
changelog.d/4842.misc
Normal file
1
changelog.d/4842.misc
Normal file
|
@ -0,0 +1 @@
|
|||
Fix integration tests and add a comment with results (still not perfect due to github actions resource limitations)
|
|
@ -1 +0,0 @@
|
|||
Translate the error observed when the user is not allowed to join a room
|
|
@ -1 +0,0 @@
|
|||
Fix github actions ktlint reports and publish results on PR as comment
|
|
@ -1 +0,0 @@
|
|||
Enabling new FTUE Auth onboarding base, includes the "I already have an account" button in the splash
|
|
@ -1 +0,0 @@
|
|||
Olm lib is now hosted in MavenCentral - upgrade to 3.2.10
|
|
@ -1 +0,0 @@
|
|||
Add ktlint results on github as a comment only on fail
|
|
@ -1 +0,0 @@
|
|||
Remove deprecated experimental restricted space lab option
|
|
@ -1 +0,0 @@
|
|||
Display Analytics opt-in screen at first start-up of the app
|
1
changelog.d/4926.misc
Normal file
1
changelog.d/4926.misc
Normal file
|
@ -0,0 +1 @@
|
|||
Add signing config for the release buildType. No secret added
|
|
@ -29,6 +29,7 @@ def vanniktechEmoji = "0.8.0"
|
|||
def mockk = "1.12.1"
|
||||
def espresso = "3.4.0"
|
||||
def androidxTest = "1.4.0"
|
||||
def androidxOrchestrator = "1.4.1"
|
||||
|
||||
|
||||
ext.libs = [
|
||||
|
@ -63,7 +64,7 @@ ext.libs = [
|
|||
'pagingRuntimeKtx' : "androidx.paging:paging-runtime-ktx:2.1.2",
|
||||
'coreTesting' : "androidx.arch.core:core-testing:2.1.0",
|
||||
'testCore' : "androidx.test:core:$androidxTest",
|
||||
'orchestrator' : "androidx.test:orchestrator:$androidxTest",
|
||||
'orchestrator' : "androidx.test:orchestrator:$androidxOrchestrator",
|
||||
'testRunner' : "androidx.test:runner:$androidxTest",
|
||||
'testRules' : "androidx.test:rules:$androidxTest",
|
||||
'espressoCore' : "androidx.test.espresso:espresso-core:$espresso",
|
||||
|
|
2
fastlane/metadata/android/en-US/changelogs/40103130.txt
Normal file
2
fastlane/metadata/android/en-US/changelogs/40103130.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
Main changes in this version: First change in onboarding screens, including Analytics opt-in. Support for Events with Math added in the labs.
|
||||
Full changelog: https://github.com/vector-im/element-android/releases/tag/v1.3.13
|
2
fastlane/metadata/android/en-US/changelogs/40103140.txt
Normal file
2
fastlane/metadata/android/en-US/changelogs/40103140.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
Main changes in this version: First change in onboarding screens, including Analytics opt-in. Support for Events with Math added in the labs.
|
||||
Full changelog: https://github.com/vector-im/element-android/releases/tag/v1.3.14
|
|
@ -25,4 +25,10 @@ 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
|
||||
#vector.httpLogLevel=BODY
|
||||
|
||||
# Dummy values for signing secrets
|
||||
signing.element.storePath=pathTo.keystore
|
||||
signing.element.storePassword=Secret
|
||||
signing.element.keyId=Secret
|
||||
signing.element.keyPassword=Secret
|
||||
|
|
3
integration_tests_script.sh
Executable file
3
integration_tests_script.sh
Executable file
|
@ -0,0 +1,3 @@
|
|||
#!/bin/bash
|
||||
./gradlew -Pandroid.testInstrumentationRunnerArguments.class=org.matrix.android.sdk.session.room.timeline.ChunkEntityTest matrix-sdk-android:connectedAndroidTest
|
||||
./gradlew -Pandroid.testInstrumentationRunnerArguments.class=org.matrix.android.sdk.session.room.timeline.TimelineForwardPaginationTest matrix-sdk-android:connectedAndroidTest
|
3
integration_tests_script_github.sh
Executable file
3
integration_tests_script_github.sh
Executable file
|
@ -0,0 +1,3 @@
|
|||
#!/bin/bash
|
||||
./gradlew $CI_GRADLE_ARG_PROPERTIES -Pandroid.testInstrumentationRunnerArguments.class=org.matrix.android.sdk.session.room.timeline.ChunkEntityTest matrix-sdk-android:connectedAndroidTest
|
||||
./gradlew $CI_GRADLE_ARG_PROPERTIES -Pandroid.testInstrumentationRunnerArguments.class=org.matrix.android.sdk.session.room.timeline.TimelineForwardPaginationTest matrix-sdk-android:connectedAndroidTest
|
|
@ -31,7 +31,7 @@ android {
|
|||
// that the app's state is completely cleared between tests.
|
||||
testInstrumentationRunnerArguments clearPackageData: 'true'
|
||||
|
||||
buildConfigField "String", "SDK_VERSION", "\"1.3.13\""
|
||||
buildConfigField "String", "SDK_VERSION", "\"1.3.16\""
|
||||
|
||||
buildConfigField "String", "GIT_SDK_REVISION", "\"${gitRevision()}\""
|
||||
resValue "string", "git_sdk_revision", "\"${gitRevision()}\""
|
||||
|
@ -66,6 +66,7 @@ android {
|
|||
|
||||
adbOptions {
|
||||
installOptions "-g"
|
||||
// timeOutInMs 350 * 1000
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
|
@ -160,7 +161,7 @@ dependencies {
|
|||
implementation libs.apache.commonsImaging
|
||||
|
||||
// Phone number https://github.com/google/libphonenumber
|
||||
implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.40'
|
||||
implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.41'
|
||||
|
||||
testImplementation libs.tests.junit
|
||||
testImplementation 'org.robolectric:robolectric:4.7.3'
|
||||
|
|
|
@ -16,7 +16,9 @@
|
|||
|
||||
package org.matrix.android.sdk.account
|
||||
|
||||
import androidx.test.filters.LargeTest
|
||||
import org.junit.FixMethodOrder
|
||||
import org.junit.Ignore
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.JUnit4
|
||||
|
@ -29,6 +31,7 @@ import org.matrix.android.sdk.common.TestConstants
|
|||
|
||||
@RunWith(JUnit4::class)
|
||||
@FixMethodOrder(MethodSorters.JVM)
|
||||
@LargeTest
|
||||
class AccountCreationTest : InstrumentedTest {
|
||||
|
||||
private val commonTestHelper = CommonTestHelper(context())
|
||||
|
@ -42,6 +45,7 @@ class AccountCreationTest : InstrumentedTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@Ignore("This test will be ignored until it is fixed")
|
||||
fun createAccountAndLoginAgainTest() {
|
||||
val session = commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(withInitialSync = true))
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ package org.matrix.android.sdk.account
|
|||
|
||||
import org.amshove.kluent.shouldBeTrue
|
||||
import org.junit.FixMethodOrder
|
||||
import org.junit.Ignore
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.JUnit4
|
||||
|
@ -30,6 +31,7 @@ import org.matrix.android.sdk.common.TestConstants
|
|||
|
||||
@RunWith(JUnit4::class)
|
||||
@FixMethodOrder(MethodSorters.JVM)
|
||||
@Ignore("This test will be ignored until it is fixed")
|
||||
class ChangePasswordTest : InstrumentedTest {
|
||||
|
||||
private val commonTestHelper = CommonTestHelper(context())
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.matrix.android.sdk.common
|
||||
|
||||
import org.junit.rules.TestRule
|
||||
import org.junit.runner.Description
|
||||
import org.junit.runners.model.Statement
|
||||
|
||||
/**
|
||||
* Retry test rule used to retry test that failed.
|
||||
* Retry failed test 3 times
|
||||
*/
|
||||
class RetryTestRule(val retryCount: Int = 3) : TestRule {
|
||||
|
||||
override fun apply(base: Statement, description: Description): Statement {
|
||||
return statement(base)
|
||||
}
|
||||
|
||||
private fun statement(base: Statement): Statement {
|
||||
return object : Statement() {
|
||||
@Throws(Throwable::class)
|
||||
override fun evaluate() {
|
||||
var caughtThrowable: Throwable? = null
|
||||
|
||||
// implement retry logic here
|
||||
for (i in 0 until retryCount) {
|
||||
try {
|
||||
base.evaluate()
|
||||
return
|
||||
} catch (t: Throwable) {
|
||||
caughtThrowable = t
|
||||
}
|
||||
}
|
||||
throw caughtThrowable!!
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -22,8 +22,8 @@ object TestConstants {
|
|||
|
||||
const val TESTS_HOME_SERVER_URL = "http://10.0.2.2:8080"
|
||||
|
||||
// Time out to use when waiting for server response. 20s
|
||||
private const val AWAIT_TIME_OUT_MILLIS = 20_000
|
||||
// Time out to use when waiting for server response.
|
||||
private const val AWAIT_TIME_OUT_MILLIS = 30_000
|
||||
|
||||
// Time out to use when waiting for server response, when the debugger is connected. 10 minutes
|
||||
private const val AWAIT_TIME_OUT_WITH_DEBUGGER_MILLIS = 10 * 60_000
|
||||
|
|
|
@ -21,6 +21,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
|
|||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertNotNull
|
||||
import org.junit.FixMethodOrder
|
||||
import org.junit.Ignore
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.MethodSorters
|
||||
|
@ -40,6 +41,7 @@ class PreShareKeysTest : InstrumentedTest {
|
|||
private val cryptoTestHelper = CryptoTestHelper(testHelper)
|
||||
|
||||
@Test
|
||||
@Ignore("This test will be ignored until it is fixed")
|
||||
fun ensure_outbound_session_happy_path() {
|
||||
val testData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true)
|
||||
val e2eRoomID = testData.roomId
|
||||
|
@ -97,7 +99,6 @@ class PreShareKeysTest : InstrumentedTest {
|
|||
}
|
||||
}
|
||||
|
||||
testHelper.signOutAndClose(aliceSession)
|
||||
testHelper.signOutAndClose(bobSession)
|
||||
testData.cleanUp(testHelper)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ import org.amshove.kluent.shouldBe
|
|||
import org.junit.Assert
|
||||
import org.junit.Before
|
||||
import org.junit.FixMethodOrder
|
||||
import org.junit.Ignore
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.MethodSorters
|
||||
|
@ -84,6 +85,7 @@ class UnwedgingTest : InstrumentedTest {
|
|||
* -> This is automatically fixed after SDKs restarted the olm session
|
||||
*/
|
||||
@Test
|
||||
@Ignore("This test will be ignored until it is fixed")
|
||||
fun testUnwedging() {
|
||||
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package org.matrix.android.sdk.internal.crypto.crosssigning
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.LargeTest
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertNotNull
|
||||
|
@ -24,6 +25,7 @@ import org.junit.Assert.assertNull
|
|||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Assert.fail
|
||||
import org.junit.FixMethodOrder
|
||||
import org.junit.Ignore
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.MethodSorters
|
||||
|
@ -43,6 +45,7 @@ import kotlin.coroutines.resume
|
|||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||
@LargeTest
|
||||
class XSigningTest : InstrumentedTest {
|
||||
|
||||
private val testHelper = CommonTestHelper(context())
|
||||
|
@ -124,11 +127,11 @@ class XSigningTest : InstrumentedTest {
|
|||
|
||||
assertFalse("Bob keys from alice pov should not be trusted", bobKeysFromAlicePOV.isTrusted())
|
||||
|
||||
testHelper.signOutAndClose(aliceSession)
|
||||
testHelper.signOutAndClose(bobSession)
|
||||
cryptoTestData.cleanUp(testHelper)
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore("This test will be ignored until it is fixed")
|
||||
fun test_CrossSigningTestAliceTrustBobNewDevice() {
|
||||
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
|
||||
|
||||
|
|
|
@ -18,12 +18,14 @@ package org.matrix.android.sdk.internal.crypto.gossiping
|
|||
|
||||
import android.util.Log
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.LargeTest
|
||||
import junit.framework.TestCase.assertEquals
|
||||
import junit.framework.TestCase.assertNotNull
|
||||
import junit.framework.TestCase.assertTrue
|
||||
import junit.framework.TestCase.fail
|
||||
import org.junit.Assert
|
||||
import org.junit.FixMethodOrder
|
||||
import org.junit.Ignore
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.MethodSorters
|
||||
|
@ -59,11 +61,13 @@ import kotlin.coroutines.resume
|
|||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@FixMethodOrder(MethodSorters.JVM)
|
||||
@LargeTest
|
||||
class KeyShareTests : InstrumentedTest {
|
||||
|
||||
private val commonTestHelper = CommonTestHelper(context())
|
||||
|
||||
@Test
|
||||
@Ignore("This test will be ignored until it is fixed")
|
||||
fun test_DoNotSelfShareIfNotTrusted() {
|
||||
val aliceSession = commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
|
||||
|
||||
|
@ -195,6 +199,7 @@ class KeyShareTests : InstrumentedTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@Ignore("This test will be ignored until it is fixed")
|
||||
fun test_ShareSSSSSecret() {
|
||||
val aliceSession1 = commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
|
||||
|
||||
|
@ -307,6 +312,7 @@ class KeyShareTests : InstrumentedTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@Ignore("This test will be ignored until it is fixed")
|
||||
fun test_ImproperKeyShareBug() {
|
||||
val aliceSession = commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
|
||||
|
||||
|
|
|
@ -18,8 +18,10 @@ package org.matrix.android.sdk.internal.crypto.gossiping
|
|||
|
||||
import android.util.Log
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.LargeTest
|
||||
import org.junit.Assert
|
||||
import org.junit.FixMethodOrder
|
||||
import org.junit.Ignore
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.MethodSorters
|
||||
|
@ -39,12 +41,14 @@ import org.matrix.android.sdk.internal.crypto.model.event.WithHeldCode
|
|||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@FixMethodOrder(MethodSorters.JVM)
|
||||
@LargeTest
|
||||
class WithHeldTests : InstrumentedTest {
|
||||
|
||||
private val testHelper = CommonTestHelper(context())
|
||||
private val cryptoTestHelper = CryptoTestHelper(testHelper)
|
||||
|
||||
@Test
|
||||
@Ignore("This test will be ignored until it is fixed")
|
||||
fun test_WithHeldUnverifiedReason() {
|
||||
// =============================
|
||||
// ARRANGE
|
||||
|
@ -129,6 +133,7 @@ class WithHeldTests : InstrumentedTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@Ignore("This test will be ignored until it is fixed")
|
||||
fun test_WithHeldNoOlm() {
|
||||
val testData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
|
||||
val aliceSession = testData.firstSession
|
||||
|
@ -199,6 +204,7 @@ class WithHeldTests : InstrumentedTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@Ignore("This test will be ignored until it is fixed")
|
||||
fun test_WithHeldKeyRequest() {
|
||||
val testData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
|
||||
val aliceSession = testData.firstSession
|
||||
|
|
|
@ -17,12 +17,14 @@
|
|||
package org.matrix.android.sdk.internal.crypto.keysbackup
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.LargeTest
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertNotNull
|
||||
import org.junit.Assert.assertNull
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.FixMethodOrder
|
||||
import org.junit.Ignore
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.MethodSorters
|
||||
|
@ -47,6 +49,7 @@ import java.util.concurrent.CountDownLatch
|
|||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@FixMethodOrder(MethodSorters.JVM)
|
||||
@LargeTest
|
||||
class KeysBackupTest : InstrumentedTest {
|
||||
|
||||
private val testHelper = CommonTestHelper(context())
|
||||
|
@ -59,6 +62,7 @@ class KeysBackupTest : InstrumentedTest {
|
|||
* - Reset keys backup markers
|
||||
*/
|
||||
@Test
|
||||
@Ignore("This test will be ignored until it is fixed")
|
||||
fun roomKeysTest_testBackupStore_ok() {
|
||||
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages()
|
||||
|
||||
|
@ -157,6 +161,7 @@ class KeysBackupTest : InstrumentedTest {
|
|||
* - Check the backup completes
|
||||
*/
|
||||
@Test
|
||||
@Ignore("This test will be ignored until it is fixed")
|
||||
fun backupAfterCreateKeysBackupVersionTest() {
|
||||
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages()
|
||||
|
||||
|
@ -197,6 +202,7 @@ class KeysBackupTest : InstrumentedTest {
|
|||
* Check that backupAllGroupSessions() returns valid data
|
||||
*/
|
||||
@Test
|
||||
@Ignore("This test will be ignored until it is fixed")
|
||||
fun backupAllGroupSessionsTest() {
|
||||
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages()
|
||||
|
||||
|
@ -241,6 +247,7 @@ class KeysBackupTest : InstrumentedTest {
|
|||
* - Compare the decrypted megolm key with the original one
|
||||
*/
|
||||
@Test
|
||||
@Ignore("This test will be ignored until it is fixed")
|
||||
fun testEncryptAndDecryptKeysBackupData() {
|
||||
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages()
|
||||
|
||||
|
@ -282,6 +289,7 @@ class KeysBackupTest : InstrumentedTest {
|
|||
* - Restore must be successful
|
||||
*/
|
||||
@Test
|
||||
@Ignore("This test will be ignored until it is fixed")
|
||||
fun restoreKeysBackupTest() {
|
||||
val testData = keysBackupTestHelper.createKeysBackupScenarioWithPassword(null)
|
||||
|
||||
|
@ -365,6 +373,7 @@ class KeysBackupTest : InstrumentedTest {
|
|||
* - It must be trusted and must have with 2 signatures now
|
||||
*/
|
||||
@Test
|
||||
@Ignore("This test will be ignored until it is fixed")
|
||||
fun trustKeyBackupVersionTest() {
|
||||
// - Do an e2e backup to the homeserver with a recovery key
|
||||
// - And log Alice on a new device
|
||||
|
@ -424,6 +433,7 @@ class KeysBackupTest : InstrumentedTest {
|
|||
* - It must be trusted and must have with 2 signatures now
|
||||
*/
|
||||
@Test
|
||||
@Ignore("This test will be ignored until it is fixed")
|
||||
fun trustKeyBackupVersionWithRecoveryKeyTest() {
|
||||
// - Do an e2e backup to the homeserver with a recovery key
|
||||
// - And log Alice on a new device
|
||||
|
@ -481,6 +491,7 @@ class KeysBackupTest : InstrumentedTest {
|
|||
* - The backup must still be untrusted and disabled
|
||||
*/
|
||||
@Test
|
||||
@Ignore("This test will be ignored until it is fixed")
|
||||
fun trustKeyBackupVersionWithWrongRecoveryKeyTest() {
|
||||
// - Do an e2e backup to the homeserver with a recovery key
|
||||
// - And log Alice on a new device
|
||||
|
@ -522,6 +533,7 @@ class KeysBackupTest : InstrumentedTest {
|
|||
* - It must be trusted and must have with 2 signatures now
|
||||
*/
|
||||
@Test
|
||||
@Ignore("This test will be ignored until it is fixed")
|
||||
fun trustKeyBackupVersionWithPasswordTest() {
|
||||
val password = "Password"
|
||||
|
||||
|
@ -581,6 +593,7 @@ class KeysBackupTest : InstrumentedTest {
|
|||
* - The backup must still be untrusted and disabled
|
||||
*/
|
||||
@Test
|
||||
@Ignore("This test will be ignored until it is fixed")
|
||||
fun trustKeyBackupVersionWithWrongPasswordTest() {
|
||||
val password = "Password"
|
||||
val badPassword = "Bad Password"
|
||||
|
@ -621,6 +634,7 @@ class KeysBackupTest : InstrumentedTest {
|
|||
* - It must fail
|
||||
*/
|
||||
@Test
|
||||
@Ignore("This test will be ignored until it is fixed")
|
||||
fun restoreKeysBackupWithAWrongRecoveryKeyTest() {
|
||||
val testData = keysBackupTestHelper.createKeysBackupScenarioWithPassword(null)
|
||||
|
||||
|
@ -654,6 +668,7 @@ class KeysBackupTest : InstrumentedTest {
|
|||
* - Restore must be successful
|
||||
*/
|
||||
@Test
|
||||
@Ignore("This test will be ignored until it is fixed")
|
||||
fun testBackupWithPassword() {
|
||||
val password = "password"
|
||||
|
||||
|
@ -709,6 +724,7 @@ class KeysBackupTest : InstrumentedTest {
|
|||
* - It must fail
|
||||
*/
|
||||
@Test
|
||||
@Ignore("This test will be ignored until it is fixed")
|
||||
fun restoreKeysBackupWithAWrongPasswordTest() {
|
||||
val password = "password"
|
||||
val wrongPassword = "passw0rd"
|
||||
|
@ -745,6 +761,7 @@ class KeysBackupTest : InstrumentedTest {
|
|||
* - Restore must be successful
|
||||
*/
|
||||
@Test
|
||||
@Ignore("This test will be ignored until it is fixed")
|
||||
fun testUseRecoveryKeyToRestoreAPasswordBasedKeysBackup() {
|
||||
val password = "password"
|
||||
|
||||
|
@ -773,6 +790,7 @@ class KeysBackupTest : InstrumentedTest {
|
|||
* - It must fail
|
||||
*/
|
||||
@Test
|
||||
@Ignore("This test will be ignored until it is fixed")
|
||||
fun testUsePasswordToRestoreARecoveryKeyBasedKeysBackup() {
|
||||
val testData = keysBackupTestHelper.createKeysBackupScenarioWithPassword(null)
|
||||
|
||||
|
@ -804,6 +822,7 @@ class KeysBackupTest : InstrumentedTest {
|
|||
* - Check the returned KeysVersionResult is trusted
|
||||
*/
|
||||
@Test
|
||||
@Ignore("This test will be ignored until it is fixed")
|
||||
fun testIsKeysBackupTrusted() {
|
||||
// - Create a backup version
|
||||
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages()
|
||||
|
@ -847,6 +866,7 @@ class KeysBackupTest : InstrumentedTest {
|
|||
* -> The new alice session must back up to the same version
|
||||
*/
|
||||
@Test
|
||||
@Ignore("This test will be ignored until it is fixed")
|
||||
fun testCheckAndStartKeysBackupWhenRestartingAMatrixSession() {
|
||||
// - Create a backup version
|
||||
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages()
|
||||
|
@ -978,6 +998,7 @@ class KeysBackupTest : InstrumentedTest {
|
|||
* -> It must success
|
||||
*/
|
||||
@Test
|
||||
@Ignore("This test will be ignored until it is fixed")
|
||||
fun testBackupAfterVerifyingADevice() {
|
||||
// - Create a backup version
|
||||
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages()
|
||||
|
|
|
@ -22,6 +22,7 @@ import org.junit.Assert.assertEquals
|
|||
import org.junit.Assert.assertNotNull
|
||||
import org.junit.Assert.assertNull
|
||||
import org.junit.FixMethodOrder
|
||||
import org.junit.Ignore
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.MethodSorters
|
||||
|
@ -47,8 +48,6 @@ import org.matrix.android.sdk.internal.crypto.secrets.DefaultSharedSecretStorage
|
|||
@FixMethodOrder(MethodSorters.JVM)
|
||||
class QuadSTests : InstrumentedTest {
|
||||
|
||||
private val testHelper = CommonTestHelper(context())
|
||||
|
||||
private val emptyKeySigner = object : KeySigner {
|
||||
override fun sign(canonicalJson: String): Map<String, Map<String, String>>? {
|
||||
return null
|
||||
|
@ -57,6 +56,8 @@ class QuadSTests : InstrumentedTest {
|
|||
|
||||
@Test
|
||||
fun test_Generate4SKey() {
|
||||
val testHelper = CommonTestHelper(context())
|
||||
|
||||
val aliceSession = testHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
|
||||
|
||||
val quadS = aliceSession.sharedSecretStorageService
|
||||
|
@ -108,6 +109,8 @@ class QuadSTests : InstrumentedTest {
|
|||
|
||||
@Test
|
||||
fun test_StoreSecret() {
|
||||
val testHelper = CommonTestHelper(context())
|
||||
|
||||
val aliceSession = testHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
|
||||
val keyId = "My.Key"
|
||||
val info = generatedSecret(aliceSession, keyId, true)
|
||||
|
@ -151,6 +154,8 @@ class QuadSTests : InstrumentedTest {
|
|||
|
||||
@Test
|
||||
fun test_SetDefaultLocalEcho() {
|
||||
val testHelper = CommonTestHelper(context())
|
||||
|
||||
val aliceSession = testHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
|
||||
|
||||
val quadS = aliceSession.sharedSecretStorageService
|
||||
|
@ -171,6 +176,8 @@ class QuadSTests : InstrumentedTest {
|
|||
|
||||
@Test
|
||||
fun test_StoreSecretWithMultipleKey() {
|
||||
val testHelper = CommonTestHelper(context())
|
||||
|
||||
val aliceSession = testHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
|
||||
val keyId1 = "Key.1"
|
||||
val key1Info = generatedSecret(aliceSession, keyId1, true)
|
||||
|
@ -217,7 +224,10 @@ class QuadSTests : InstrumentedTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@Ignore("Test is working locally, not in GitHub actions")
|
||||
fun test_GetSecretWithBadPassphrase() {
|
||||
val testHelper = CommonTestHelper(context())
|
||||
|
||||
val aliceSession = testHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
|
||||
val keyId1 = "Key.1"
|
||||
val passphrase = "The good pass phrase"
|
||||
|
@ -264,6 +274,8 @@ class QuadSTests : InstrumentedTest {
|
|||
}
|
||||
|
||||
private fun assertAccountData(session: Session, type: String): UserAccountDataEvent {
|
||||
val testHelper = CommonTestHelper(context())
|
||||
|
||||
var accountData: UserAccountDataEvent? = null
|
||||
testHelper.waitWithLatch {
|
||||
val liveAccountData = session.accountDataService().getLiveUserAccountDataEvent(type)
|
||||
|
@ -281,6 +293,7 @@ class QuadSTests : InstrumentedTest {
|
|||
|
||||
private fun generatedSecret(session: Session, keyId: String, asDefault: Boolean = true): SsssKeyCreationInfo {
|
||||
val quadS = session.sharedSecretStorageService
|
||||
val testHelper = CommonTestHelper(context())
|
||||
|
||||
val creationInfo = testHelper.runBlockingTest {
|
||||
quadS.generateKey(keyId, null, keyId, emptyKeySigner)
|
||||
|
@ -300,6 +313,7 @@ class QuadSTests : InstrumentedTest {
|
|||
|
||||
private fun generatedSecretFromPassphrase(session: Session, passphrase: String, keyId: String, asDefault: Boolean = true): SsssKeyCreationInfo {
|
||||
val quadS = session.sharedSecretStorageService
|
||||
val testHelper = CommonTestHelper(context())
|
||||
|
||||
val creationInfo = testHelper.runBlockingTest {
|
||||
quadS.generateKeyWithPassphrase(
|
||||
|
|
|
@ -25,6 +25,7 @@ import org.junit.Assert.assertNull
|
|||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Assert.fail
|
||||
import org.junit.FixMethodOrder
|
||||
import org.junit.Ignore
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.MethodSorters
|
||||
|
@ -53,11 +54,11 @@ import java.util.concurrent.CountDownLatch
|
|||
@RunWith(AndroidJUnit4::class)
|
||||
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||
class SASTest : InstrumentedTest {
|
||||
private val testHelper = CommonTestHelper(context())
|
||||
private val cryptoTestHelper = CryptoTestHelper(testHelper)
|
||||
|
||||
@Test
|
||||
fun test_aliceStartThenAliceCancel() {
|
||||
val testHelper = CommonTestHelper(context())
|
||||
val cryptoTestHelper = CryptoTestHelper(testHelper)
|
||||
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
|
||||
|
||||
val aliceSession = cryptoTestData.firstSession
|
||||
|
@ -137,7 +138,10 @@ class SASTest : InstrumentedTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@Ignore("This test will be ignored until it is fixed")
|
||||
fun test_key_agreement_protocols_must_include_curve25519() {
|
||||
val testHelper = CommonTestHelper(context())
|
||||
val cryptoTestHelper = CryptoTestHelper(testHelper)
|
||||
fail("Not passing for the moment")
|
||||
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
|
||||
|
||||
|
@ -194,7 +198,10 @@ class SASTest : InstrumentedTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@Ignore("This test will be ignored until it is fixed")
|
||||
fun test_key_agreement_macs_Must_include_hmac_sha256() {
|
||||
val testHelper = CommonTestHelper(context())
|
||||
val cryptoTestHelper = CryptoTestHelper(testHelper)
|
||||
fail("Not passing for the moment")
|
||||
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
|
||||
|
||||
|
@ -232,7 +239,10 @@ class SASTest : InstrumentedTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@Ignore("This test will be ignored until it is fixed")
|
||||
fun test_key_agreement_short_code_include_decimal() {
|
||||
val testHelper = CommonTestHelper(context())
|
||||
val cryptoTestHelper = CryptoTestHelper(testHelper)
|
||||
fail("Not passing for the moment")
|
||||
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
|
||||
|
||||
|
@ -303,6 +313,8 @@ class SASTest : InstrumentedTest {
|
|||
// If a device has two verifications in progress with the same device, then it should cancel both verifications.
|
||||
@Test
|
||||
fun test_aliceStartTwoRequests() {
|
||||
val testHelper = CommonTestHelper(context())
|
||||
val cryptoTestHelper = CryptoTestHelper(testHelper)
|
||||
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
|
||||
|
||||
val aliceSession = cryptoTestData.firstSession
|
||||
|
@ -342,7 +354,10 @@ class SASTest : InstrumentedTest {
|
|||
* Test that when alice starts a 'correct' request, bob agrees.
|
||||
*/
|
||||
@Test
|
||||
@Ignore("This test will be ignored until it is fixed")
|
||||
fun test_aliceAndBobAgreement() {
|
||||
val testHelper = CommonTestHelper(context())
|
||||
val cryptoTestHelper = CryptoTestHelper(testHelper)
|
||||
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
|
||||
|
||||
val aliceSession = cryptoTestData.firstSession
|
||||
|
@ -402,6 +417,8 @@ class SASTest : InstrumentedTest {
|
|||
|
||||
@Test
|
||||
fun test_aliceAndBobSASCode() {
|
||||
val testHelper = CommonTestHelper(context())
|
||||
val cryptoTestHelper = CryptoTestHelper(testHelper)
|
||||
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
|
||||
|
||||
val aliceSession = cryptoTestData.firstSession
|
||||
|
@ -458,6 +475,8 @@ class SASTest : InstrumentedTest {
|
|||
|
||||
@Test
|
||||
fun test_happyPath() {
|
||||
val testHelper = CommonTestHelper(context())
|
||||
val cryptoTestHelper = CryptoTestHelper(testHelper)
|
||||
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
|
||||
|
||||
val aliceSession = cryptoTestData.firstSession
|
||||
|
@ -527,9 +546,6 @@ class SASTest : InstrumentedTest {
|
|||
val bobDeviceInfoFromAlicePOV: CryptoDeviceInfo? = aliceSession.cryptoService().getDeviceInfo(bobUserId, bobDeviceId)
|
||||
val aliceDeviceInfoFromBobPOV: CryptoDeviceInfo? = bobSession.cryptoService().getDeviceInfo(aliceSession.myUserId, aliceSession.cryptoService().getMyDevice().deviceId)
|
||||
|
||||
// latch wait a bit again
|
||||
Thread.sleep(1000)
|
||||
|
||||
assertTrue("alice device should be verified from bob point of view", aliceDeviceInfoFromBobPOV!!.isVerified)
|
||||
assertTrue("bob device should be verified from alice point of view", bobDeviceInfoFromAlicePOV!!.isVerified)
|
||||
cryptoTestData.cleanUp(testHelper)
|
||||
|
@ -537,6 +553,8 @@ class SASTest : InstrumentedTest {
|
|||
|
||||
@Test
|
||||
fun test_ConcurrentStart() {
|
||||
val testHelper = CommonTestHelper(context())
|
||||
val cryptoTestHelper = CryptoTestHelper(testHelper)
|
||||
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
|
||||
|
||||
val aliceSession = cryptoTestData.firstSession
|
||||
|
|
|
@ -40,8 +40,6 @@ import kotlin.coroutines.resume
|
|||
@RunWith(AndroidJUnit4::class)
|
||||
@FixMethodOrder(MethodSorters.JVM)
|
||||
class VerificationTest : InstrumentedTest {
|
||||
private val testHelper = CommonTestHelper(context())
|
||||
private val cryptoTestHelper = CryptoTestHelper(testHelper)
|
||||
|
||||
data class ExpectedResult(
|
||||
val sasIsSupported: Boolean = false,
|
||||
|
@ -155,6 +153,8 @@ class VerificationTest : InstrumentedTest {
|
|||
bobSupportedMethods: List<VerificationMethod>,
|
||||
expectedResultForAlice: ExpectedResult,
|
||||
expectedResultForBob: ExpectedResult) {
|
||||
val testHelper = CommonTestHelper(context())
|
||||
val cryptoTestHelper = CryptoTestHelper(testHelper)
|
||||
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
|
||||
|
||||
val aliceSession = cryptoTestData.firstSession
|
||||
|
|
|
@ -21,6 +21,7 @@ import org.commonmark.parser.Parser
|
|||
import org.commonmark.renderer.html.HtmlRenderer
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.FixMethodOrder
|
||||
import org.junit.Ignore
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.MethodSorters
|
||||
|
@ -132,6 +133,7 @@ class MarkdownParserTest : InstrumentedTest {
|
|||
* Note: the test is not passing, it does not work on Element Web neither
|
||||
*/
|
||||
@Test
|
||||
@Ignore("This test will be ignored until it is fixed")
|
||||
fun parseStrike_not_passing() {
|
||||
testType(
|
||||
name = "strike",
|
||||
|
@ -141,6 +143,7 @@ class MarkdownParserTest : InstrumentedTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@Ignore("This test will be ignored until it is fixed")
|
||||
fun parseStrikeNewLines() {
|
||||
testTypeNewLines(
|
||||
name = "strike",
|
||||
|
@ -160,6 +163,7 @@ class MarkdownParserTest : InstrumentedTest {
|
|||
|
||||
// TODO. Improve testTypeNewLines function to cover <pre><code class="language-code">test</code></pre>
|
||||
@Test
|
||||
@Ignore("This test will be ignored until it is fixed")
|
||||
fun parseCodeNewLines_not_passing() {
|
||||
testTypeNewLines(
|
||||
name = "code",
|
||||
|
@ -179,6 +183,7 @@ class MarkdownParserTest : InstrumentedTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@Ignore("This test will be ignored until it is fixed")
|
||||
fun parseCode2NewLines_not_passing() {
|
||||
testTypeNewLines(
|
||||
name = "code",
|
||||
|
@ -197,6 +202,7 @@ class MarkdownParserTest : InstrumentedTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@Ignore("This test will be ignored until it is fixed")
|
||||
fun parseCode3NewLines_not_passing() {
|
||||
testTypeNewLines(
|
||||
name = "code",
|
||||
|
@ -233,6 +239,7 @@ class MarkdownParserTest : InstrumentedTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@Ignore("This test will be ignored until it is fixed")
|
||||
fun parseQuote_not_passing() {
|
||||
"> quoted\nline2".let { markdownParser.parse(it).expect(it, "<blockquote><p>quoted<br />line2</p></blockquote>") }
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.matrix.android.sdk
|
||||
package org.matrix.android.sdk.ordering
|
||||
|
||||
import org.amshove.kluent.internal.assertEquals
|
||||
import org.junit.Assert
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.matrix.android.sdk
|
||||
package org.matrix.android.sdk.ordering
|
||||
|
||||
import org.amshove.kluent.internal.assertEquals
|
||||
import org.junit.Assert
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package org.matrix.android.sdk.session.room.timeline
|
||||
|
||||
import androidx.test.filters.LargeTest
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.amshove.kluent.internal.assertEquals
|
||||
import org.amshove.kluent.shouldBeFalse
|
||||
|
@ -40,16 +41,20 @@ import java.util.concurrent.CountDownLatch
|
|||
|
||||
@RunWith(JUnit4::class)
|
||||
@FixMethodOrder(MethodSorters.JVM)
|
||||
@LargeTest
|
||||
class TimelineForwardPaginationTest : InstrumentedTest {
|
||||
|
||||
private val commonTestHelper = CommonTestHelper(context())
|
||||
private val cryptoTestHelper = CryptoTestHelper(commonTestHelper)
|
||||
// @Rule
|
||||
// @JvmField
|
||||
// val mRetryTestRule = RetryTestRule()
|
||||
|
||||
/**
|
||||
* This test ensure that if we click to permalink, we will be able to go back to the live
|
||||
*/
|
||||
@Test
|
||||
fun forwardPaginationTest() {
|
||||
val commonTestHelper = CommonTestHelper(context())
|
||||
val cryptoTestHelper = CryptoTestHelper(commonTestHelper)
|
||||
val numberOfMessagesToSend = 90
|
||||
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceInARoom(false)
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package org.matrix.android.sdk.session.room.timeline
|
||||
|
||||
import androidx.test.filters.LargeTest
|
||||
import org.amshove.kluent.shouldBeFalse
|
||||
import org.amshove.kluent.shouldBeTrue
|
||||
import org.junit.FixMethodOrder
|
||||
|
@ -38,16 +39,17 @@ import java.util.concurrent.CountDownLatch
|
|||
|
||||
@RunWith(JUnit4::class)
|
||||
@FixMethodOrder(MethodSorters.JVM)
|
||||
@LargeTest
|
||||
class TimelinePreviousLastForwardTest : InstrumentedTest {
|
||||
|
||||
private val commonTestHelper = CommonTestHelper(context())
|
||||
private val cryptoTestHelper = CryptoTestHelper(commonTestHelper)
|
||||
|
||||
/**
|
||||
* This test ensure that if we have a chunk in the timeline which is due to a sync, and we click to permalink, we will be able to go back to the live
|
||||
*/
|
||||
|
||||
@Test
|
||||
fun previousLastForwardTest() {
|
||||
val commonTestHelper = CommonTestHelper(context())
|
||||
val cryptoTestHelper = CryptoTestHelper(commonTestHelper)
|
||||
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(false)
|
||||
|
||||
val aliceSession = cryptoTestData.firstSession
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package org.matrix.android.sdk.session.room.timeline
|
||||
|
||||
import androidx.test.filters.LargeTest
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.amshove.kluent.internal.assertEquals
|
||||
import org.junit.FixMethodOrder
|
||||
|
@ -36,13 +37,13 @@ import org.matrix.android.sdk.common.TestConstants
|
|||
|
||||
@RunWith(JUnit4::class)
|
||||
@FixMethodOrder(MethodSorters.JVM)
|
||||
@LargeTest
|
||||
class TimelineSimpleBackPaginationTest : InstrumentedTest {
|
||||
|
||||
private val commonTestHelper = CommonTestHelper(context())
|
||||
private val cryptoTestHelper = CryptoTestHelper(commonTestHelper)
|
||||
|
||||
@Test
|
||||
fun timeline_backPaginate_shouldReachEndOfTimeline() {
|
||||
val commonTestHelper = CommonTestHelper(context())
|
||||
val cryptoTestHelper = CryptoTestHelper(commonTestHelper)
|
||||
val numberOfMessagesToSent = 200
|
||||
|
||||
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(false)
|
||||
|
|
|
@ -16,8 +16,10 @@
|
|||
|
||||
package org.matrix.android.sdk.session.room.timeline
|
||||
|
||||
import androidx.test.filters.LargeTest
|
||||
import org.junit.Assert.fail
|
||||
import org.junit.FixMethodOrder
|
||||
import org.junit.Ignore
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.JUnit4
|
||||
|
@ -31,8 +33,13 @@ import org.matrix.android.sdk.common.CommonTestHelper
|
|||
import org.matrix.android.sdk.common.CryptoTestHelper
|
||||
import java.util.concurrent.CountDownLatch
|
||||
|
||||
/** !! Not working with the new timeline
|
||||
* Disabling it until the fix is made
|
||||
*/
|
||||
@RunWith(JUnit4::class)
|
||||
@FixMethodOrder(MethodSorters.JVM)
|
||||
@Ignore("This test will be ignored until it is fixed")
|
||||
@LargeTest
|
||||
class TimelineWithManyMembersTest : InstrumentedTest {
|
||||
|
||||
companion object {
|
||||
|
@ -45,6 +52,7 @@ class TimelineWithManyMembersTest : InstrumentedTest {
|
|||
/**
|
||||
* Ensures when someone sends a message to a crowded room, everyone can decrypt the message.
|
||||
*/
|
||||
|
||||
@Test
|
||||
fun everyone_should_decrypt_message_in_a_crowded_room() {
|
||||
val cryptoTestData = cryptoTestHelper.doE2ETestWithManyMembers(NUMBER_OF_MEMBERS)
|
||||
|
|
|
@ -37,9 +37,6 @@ class SearchMessagesTest : InstrumentedTest {
|
|||
private const val MESSAGE = "Lorem ipsum dolor sit amet"
|
||||
}
|
||||
|
||||
private val commonTestHelper = CommonTestHelper(context())
|
||||
private val cryptoTestHelper = CryptoTestHelper(commonTestHelper)
|
||||
|
||||
@Test
|
||||
fun sendTextMessageAndSearchPartOfItUsingSession() {
|
||||
doTest { cryptoTestData ->
|
||||
|
@ -76,6 +73,8 @@ class SearchMessagesTest : InstrumentedTest {
|
|||
}
|
||||
|
||||
private fun doTest(block: suspend (CryptoTestData) -> SearchResult) {
|
||||
val commonTestHelper = CommonTestHelper(context())
|
||||
val cryptoTestHelper = CryptoTestHelper(commonTestHelper)
|
||||
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceInARoom(false)
|
||||
val aliceSession = cryptoTestData.firstSession
|
||||
val aliceRoomId = cryptoTestData.roomId
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package org.matrix.android.sdk.session.space
|
||||
|
||||
import androidx.test.filters.LargeTest
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.Assert.assertEquals
|
||||
|
@ -43,12 +44,12 @@ import org.matrix.android.sdk.common.SessionTestParams
|
|||
|
||||
@RunWith(JUnit4::class)
|
||||
@FixMethodOrder(MethodSorters.JVM)
|
||||
@LargeTest
|
||||
class SpaceCreationTest : InstrumentedTest {
|
||||
|
||||
private val commonTestHelper = CommonTestHelper(context())
|
||||
|
||||
@Test
|
||||
fun createSimplePublicSpace() {
|
||||
val commonTestHelper = CommonTestHelper(context())
|
||||
val session = commonTestHelper.createAccount("Hubble", SessionTestParams(true))
|
||||
val roomName = "My Space"
|
||||
val topic = "A public space for test"
|
||||
|
@ -58,6 +59,7 @@ class SpaceCreationTest : InstrumentedTest {
|
|||
// wait a bit to let the summary update it self :/
|
||||
it.countDown()
|
||||
}
|
||||
Thread.sleep(4_000)
|
||||
|
||||
val syncedSpace = session.spaceService().getSpace(spaceId)
|
||||
commonTestHelper.waitWithLatch {
|
||||
|
@ -99,6 +101,8 @@ class SpaceCreationTest : InstrumentedTest {
|
|||
|
||||
@Test
|
||||
fun testJoinSimplePublicSpace() {
|
||||
val commonTestHelper = CommonTestHelper(context())
|
||||
|
||||
val aliceSession = commonTestHelper.createAccount("alice", SessionTestParams(true))
|
||||
val bobSession = commonTestHelper.createAccount("bob", SessionTestParams(true))
|
||||
|
||||
|
@ -130,6 +134,7 @@ class SpaceCreationTest : InstrumentedTest {
|
|||
|
||||
@Test
|
||||
fun testSimplePublicSpaceWithChildren() {
|
||||
val commonTestHelper = CommonTestHelper(context())
|
||||
val aliceSession = commonTestHelper.createAccount("alice", SessionTestParams(true))
|
||||
val bobSession = commonTestHelper.createAccount("bob", SessionTestParams(true))
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ import org.junit.Assert.assertEquals
|
|||
import org.junit.Assert.assertNotNull
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.FixMethodOrder
|
||||
import org.junit.Ignore
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.JUnit4
|
||||
|
@ -50,10 +51,10 @@ import org.matrix.android.sdk.common.SessionTestParams
|
|||
@FixMethodOrder(MethodSorters.JVM)
|
||||
class SpaceHierarchyTest : InstrumentedTest {
|
||||
|
||||
private val commonTestHelper = CommonTestHelper(context())
|
||||
|
||||
@Test
|
||||
fun createCanonicalChildRelation() {
|
||||
val commonTestHelper = CommonTestHelper(context())
|
||||
|
||||
val session = commonTestHelper.createAccount("John", SessionTestParams(true))
|
||||
val spaceName = "My Space"
|
||||
val topic = "A public space for test"
|
||||
|
@ -170,6 +171,7 @@ class SpaceHierarchyTest : InstrumentedTest {
|
|||
|
||||
@Test
|
||||
fun testFilteringBySpace() {
|
||||
val commonTestHelper = CommonTestHelper(context())
|
||||
val session = commonTestHelper.createAccount("John", SessionTestParams(true))
|
||||
|
||||
val spaceAInfo = createPublicSpace(session, "SpaceA", listOf(
|
||||
|
@ -236,7 +238,7 @@ class SpaceHierarchyTest : InstrumentedTest {
|
|||
it.countDown()
|
||||
}
|
||||
|
||||
Thread.sleep(2_000)
|
||||
Thread.sleep(6_000)
|
||||
val orphansUpdate = session.getRoomSummaries(roomSummaryQueryParams {
|
||||
activeSpaceFilter = ActiveSpaceFilter.ActiveSpace(null)
|
||||
})
|
||||
|
@ -244,7 +246,9 @@ class SpaceHierarchyTest : InstrumentedTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@Ignore("This test will be ignored until it is fixed")
|
||||
fun testBreakCycle() {
|
||||
val commonTestHelper = CommonTestHelper(context())
|
||||
val session = commonTestHelper.createAccount("John", SessionTestParams(true))
|
||||
|
||||
val spaceAInfo = createPublicSpace(session, "SpaceA", listOf(
|
||||
|
@ -273,8 +277,6 @@ class SpaceHierarchyTest : InstrumentedTest {
|
|||
it.countDown()
|
||||
}
|
||||
|
||||
Thread.sleep(1000)
|
||||
|
||||
// A -> C -> A
|
||||
|
||||
val aChildren = session.getFlattenRoomSummaryChildrenOf(spaceAInfo.spaceId)
|
||||
|
@ -288,6 +290,7 @@ class SpaceHierarchyTest : InstrumentedTest {
|
|||
|
||||
@Test
|
||||
fun testLiveFlatChildren() {
|
||||
val commonTestHelper = CommonTestHelper(context())
|
||||
val session = commonTestHelper.createAccount("John", SessionTestParams(true))
|
||||
|
||||
val spaceAInfo = createPublicSpace(session, "SpaceA", listOf(
|
||||
|
@ -374,6 +377,7 @@ class SpaceHierarchyTest : InstrumentedTest {
|
|||
childInfo: List<Triple<String, Boolean, Boolean?>>
|
||||
/** Name, auto-join, canonical*/
|
||||
): TestSpaceCreationResult {
|
||||
val commonTestHelper = CommonTestHelper(context())
|
||||
var spaceId = ""
|
||||
var roomIds: List<String> = emptyList()
|
||||
commonTestHelper.waitWithLatch { latch ->
|
||||
|
@ -401,6 +405,7 @@ class SpaceHierarchyTest : InstrumentedTest {
|
|||
childInfo: List<Triple<String, Boolean, Boolean?>>
|
||||
/** Name, auto-join, canonical*/
|
||||
): TestSpaceCreationResult {
|
||||
val commonTestHelper = CommonTestHelper(context())
|
||||
var spaceId = ""
|
||||
var roomIds: List<String> = emptyList()
|
||||
commonTestHelper.waitWithLatch { latch ->
|
||||
|
@ -435,6 +440,7 @@ class SpaceHierarchyTest : InstrumentedTest {
|
|||
|
||||
@Test
|
||||
fun testRootSpaces() {
|
||||
val commonTestHelper = CommonTestHelper(context())
|
||||
val session = commonTestHelper.createAccount("John", SessionTestParams(true))
|
||||
|
||||
/* val spaceAInfo = */ createPublicSpace(session, "SpaceA", listOf(
|
||||
|
@ -459,9 +465,10 @@ class SpaceHierarchyTest : InstrumentedTest {
|
|||
runBlocking {
|
||||
val spaceB = session.spaceService().getSpace(spaceBInfo.spaceId)
|
||||
spaceB!!.addChildren(spaceCInfo.spaceId, viaServers, null, true)
|
||||
Thread.sleep(6_000)
|
||||
}
|
||||
|
||||
Thread.sleep(2000)
|
||||
// Thread.sleep(4_000)
|
||||
// + A
|
||||
// a1, a2
|
||||
// + B
|
||||
|
@ -478,6 +485,7 @@ class SpaceHierarchyTest : InstrumentedTest {
|
|||
|
||||
@Test
|
||||
fun testParentRelation() {
|
||||
val commonTestHelper = CommonTestHelper(context())
|
||||
val aliceSession = commonTestHelper.createAccount("Alice", SessionTestParams(true))
|
||||
val bobSession = commonTestHelper.createAccount("Bib", SessionTestParams(true))
|
||||
|
||||
|
|
|
@ -27,5 +27,8 @@ enum class RoomEncryptionTrustLevel {
|
|||
Warning,
|
||||
|
||||
// All devices in the room are verified -> the app should display a green shield
|
||||
Trusted
|
||||
Trusted,
|
||||
|
||||
// e2e is active but with an unsupported algorithm
|
||||
E2EWithUnsupportedAlgorithm
|
||||
}
|
||||
|
|
|
@ -27,9 +27,12 @@ interface RoomCryptoService {
|
|||
fun shouldEncryptForInvitedMembers(): Boolean
|
||||
|
||||
/**
|
||||
* Enable encryption of the room
|
||||
* Enable encryption of the room.
|
||||
* @param Use force to ensure that this algorithm will be used. Otherwise this call
|
||||
* will throw if encryption is already setup or if the algorithm is not supported. Only to
|
||||
* be used by admins to fix misconfigured encryption.
|
||||
*/
|
||||
suspend fun enableEncryption(algorithm: String = MXCRYPTO_ALGORITHM_MEGOLM)
|
||||
suspend fun enableEncryption(algorithm: String = MXCRYPTO_ALGORITHM_MEGOLM, force: Boolean = false)
|
||||
|
||||
/**
|
||||
* Ensures all members of the room are loaded and outbound session keys are shared.
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* 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 org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM
|
||||
|
||||
sealed class RoomEncryptionAlgorithm {
|
||||
|
||||
abstract class SupportedAlgorithm(val alg: String) : RoomEncryptionAlgorithm()
|
||||
|
||||
object Megolm : SupportedAlgorithm(MXCRYPTO_ALGORITHM_MEGOLM)
|
||||
|
||||
data class UnsupportedAlgorithm(val name: String?) : RoomEncryptionAlgorithm()
|
||||
}
|
|
@ -62,7 +62,8 @@ data class RoomSummary(
|
|||
val roomType: String? = null,
|
||||
val spaceParents: List<SpaceParentInfo>? = null,
|
||||
val spaceChildren: List<SpaceChildInfo>? = null,
|
||||
val flattenParentIds: List<String> = emptyList()
|
||||
val flattenParentIds: List<String> = emptyList(),
|
||||
val roomEncryptionAlgorithm: RoomEncryptionAlgorithm? = null
|
||||
) {
|
||||
|
||||
val isVersioned: Boolean
|
||||
|
|
|
@ -37,7 +37,6 @@ internal class CryptoSessionInfoProvider @Inject constructor(
|
|||
fun isRoomEncrypted(roomId: String): Boolean {
|
||||
val encryptionEvent = monarchy.fetchCopied { realm ->
|
||||
EventEntity.whereType(realm, roomId = roomId, type = EventType.STATE_ROOM_ENCRYPTION)
|
||||
.contains(EventEntityFields.CONTENT, "\"algorithm\":\"$MXCRYPTO_ALGORITHM_MEGOLM\"")
|
||||
.isEmpty(EventEntityFields.STATE_KEY)
|
||||
.findFirst()
|
||||
}
|
||||
|
|
|
@ -177,7 +177,7 @@ internal class DefaultCryptoService @Inject constructor(
|
|||
private val isStarted = AtomicBoolean(false)
|
||||
|
||||
fun onStateEvent(roomId: String, event: Event) {
|
||||
when (event.getClearType()) {
|
||||
when (event.type) {
|
||||
EventType.STATE_ROOM_ENCRYPTION -> onRoomEncryptionEvent(roomId, event)
|
||||
EventType.STATE_ROOM_MEMBER -> onRoomMembershipEvent(roomId, event)
|
||||
EventType.STATE_ROOM_HISTORY_VISIBILITY -> onRoomHistoryVisibilityEvent(roomId, event)
|
||||
|
@ -185,10 +185,13 @@ internal class DefaultCryptoService @Inject constructor(
|
|||
}
|
||||
|
||||
fun onLiveEvent(roomId: String, event: Event) {
|
||||
when (event.getClearType()) {
|
||||
EventType.STATE_ROOM_ENCRYPTION -> onRoomEncryptionEvent(roomId, event)
|
||||
EventType.STATE_ROOM_MEMBER -> onRoomMembershipEvent(roomId, event)
|
||||
EventType.STATE_ROOM_HISTORY_VISIBILITY -> onRoomHistoryVisibilityEvent(roomId, event)
|
||||
// handle state events
|
||||
if (event.isStateEvent()) {
|
||||
when (event.type) {
|
||||
EventType.STATE_ROOM_ENCRYPTION -> onRoomEncryptionEvent(roomId, event)
|
||||
EventType.STATE_ROOM_MEMBER -> onRoomMembershipEvent(roomId, event)
|
||||
EventType.STATE_ROOM_HISTORY_VISIBILITY -> onRoomHistoryVisibilityEvent(roomId, event)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -575,26 +578,31 @@ internal class DefaultCryptoService @Inject constructor(
|
|||
// (for now at least. Maybe we should alert the user somehow?)
|
||||
val existingAlgorithm = cryptoStore.getRoomAlgorithm(roomId)
|
||||
|
||||
if (!existingAlgorithm.isNullOrEmpty() && existingAlgorithm != algorithm) {
|
||||
Timber.tag(loggerTag.value).e("setEncryptionInRoom() : Ignoring m.room.encryption event which requests a change of config in $roomId")
|
||||
if (existingAlgorithm == algorithm && roomEncryptorsStore.get(roomId) != null) {
|
||||
// ignore
|
||||
Timber.tag(loggerTag.value).e("setEncryptionInRoom() : Ignoring m.room.encryption for same alg ($algorithm) in $roomId")
|
||||
return false
|
||||
}
|
||||
|
||||
val encryptingClass = MXCryptoAlgorithms.hasEncryptorClassForAlgorithm(algorithm)
|
||||
|
||||
// Always store even if not supported
|
||||
cryptoStore.storeRoomAlgorithm(roomId, algorithm)
|
||||
|
||||
if (!encryptingClass) {
|
||||
Timber.tag(loggerTag.value).e("setEncryptionInRoom() : Unable to encrypt room $roomId with $algorithm")
|
||||
return false
|
||||
}
|
||||
|
||||
cryptoStore.storeRoomAlgorithm(roomId, algorithm!!)
|
||||
|
||||
val alg: IMXEncrypting = when (algorithm) {
|
||||
val alg: IMXEncrypting? = when (algorithm) {
|
||||
MXCRYPTO_ALGORITHM_MEGOLM -> megolmEncryptionFactory.create(roomId)
|
||||
else -> olmEncryptionFactory.create(roomId)
|
||||
MXCRYPTO_ALGORITHM_OLM -> olmEncryptionFactory.create(roomId)
|
||||
else -> null
|
||||
}
|
||||
|
||||
roomEncryptorsStore.put(roomId, alg)
|
||||
if (alg != null) {
|
||||
roomEncryptorsStore.put(roomId, alg)
|
||||
}
|
||||
|
||||
// if encryption was not previously enabled in this room, we will have been
|
||||
// ignoring new device events for these users so far. We may well have
|
||||
|
@ -927,6 +935,7 @@ internal class DefaultCryptoService @Inject constructor(
|
|||
}
|
||||
|
||||
private fun onRoomHistoryVisibilityEvent(roomId: String, event: Event) {
|
||||
if (!event.isStateEvent()) return
|
||||
val eventContent = event.content.toModel<RoomHistoryVisibilityContent>()
|
||||
eventContent?.historyVisibility?.let {
|
||||
cryptoStore.setShouldEncryptForInvitedMembers(roomId, it != RoomHistoryVisibility.JOINED)
|
||||
|
|
|
@ -27,7 +27,7 @@ data class EncryptionEventContent(
|
|||
* Required. The encryption algorithm to be used to encrypt messages sent in this room. Must be 'm.megolm.v1.aes-sha2'.
|
||||
*/
|
||||
@Json(name = "algorithm")
|
||||
val algorithm: String,
|
||||
val algorithm: String?,
|
||||
|
||||
/**
|
||||
* How long the session should be used before changing it. 604800000 (a week) is the recommended default.
|
||||
|
|
|
@ -230,7 +230,7 @@ internal interface IMXCryptoStore {
|
|||
* @param roomId the id of the room.
|
||||
* @param algorithm the algorithm.
|
||||
*/
|
||||
fun storeRoomAlgorithm(roomId: String, algorithm: String)
|
||||
fun storeRoomAlgorithm(roomId: String, algorithm: String?)
|
||||
|
||||
/**
|
||||
* Provides the algorithm used in a dedicated room.
|
||||
|
|
|
@ -629,7 +629,7 @@ internal class RealmCryptoStore @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
override fun storeRoomAlgorithm(roomId: String, algorithm: String) {
|
||||
override fun storeRoomAlgorithm(roomId: String, algorithm: String?) {
|
||||
doRealmTransaction(realmConfiguration) {
|
||||
CryptoRoomEntity.getOrCreate(it, roomId).algorithm = algorithm
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ 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.model.tag.RoomTag
|
||||
import org.matrix.android.sdk.api.session.threads.ThreadNotificationState
|
||||
import org.matrix.android.sdk.internal.crypto.model.event.EncryptionEventContent
|
||||
import org.matrix.android.sdk.internal.database.model.ChunkEntityFields
|
||||
import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntityFields
|
||||
import org.matrix.android.sdk.internal.database.model.EditAggregatedSummaryEntityFields
|
||||
|
@ -56,7 +57,7 @@ internal class RealmSessionStoreMigration @Inject constructor(
|
|||
) : RealmMigration {
|
||||
|
||||
companion object {
|
||||
const val SESSION_STORE_SCHEMA_VERSION = 21L
|
||||
const val SESSION_STORE_SCHEMA_VERSION = 22L
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -397,6 +398,7 @@ internal class RealmSessionStoreMigration @Inject constructor(
|
|||
|
||||
private fun migrateTo20(realm: DynamicRealm) {
|
||||
Timber.d("Step 19 -> 20")
|
||||
|
||||
realm.schema.get("ChunkEntity")?.apply {
|
||||
if (hasField("numberOfTimelineEvents")) {
|
||||
removeField("numberOfTimelineEvents")
|
||||
|
@ -419,6 +421,34 @@ internal class RealmSessionStoreMigration @Inject constructor(
|
|||
|
||||
private fun migrateTo21(realm: DynamicRealm) {
|
||||
Timber.d("Step 20 -> 21")
|
||||
|
||||
realm.schema.get("RoomSummaryEntity")
|
||||
?.addField(RoomSummaryEntityFields.E2E_ALGORITHM, String::class.java)
|
||||
?.transform { obj ->
|
||||
|
||||
val encryptionContentAdapter = MoshiProvider.providesMoshi().adapter(EncryptionEventContent::class.java)
|
||||
|
||||
val encryptionEvent = realm.where("CurrentStateEventEntity")
|
||||
.equalTo(CurrentStateEventEntityFields.ROOM_ID, obj.getString(RoomSummaryEntityFields.ROOM_ID))
|
||||
.equalTo(CurrentStateEventEntityFields.TYPE, EventType.STATE_ROOM_ENCRYPTION)
|
||||
.findFirst()
|
||||
|
||||
val encryptionEventRoot = encryptionEvent?.getObject(CurrentStateEventEntityFields.ROOT.`$`)
|
||||
val algorithm = encryptionEventRoot
|
||||
?.getString(EventEntityFields.CONTENT)?.let {
|
||||
encryptionContentAdapter.fromJson(it)?.algorithm
|
||||
}
|
||||
|
||||
obj.setString(RoomSummaryEntityFields.E2E_ALGORITHM, algorithm)
|
||||
obj.setBoolean(RoomSummaryEntityFields.IS_ENCRYPTED, encryptionEvent != null)
|
||||
encryptionEventRoot?.getLong(EventEntityFields.ORIGIN_SERVER_TS)?.let {
|
||||
obj.setLong(RoomSummaryEntityFields.ENCRYPTION_EVENT_TS, it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun migrateTo21(realm: DynamicRealm) {
|
||||
Timber.d("Step 21 -> 22")
|
||||
val eventEntity = realm.schema.get("TimelineEventEntity") ?: return
|
||||
|
||||
realm.schema.get("EventEntity")
|
||||
|
|
|
@ -30,8 +30,8 @@ internal fun TimelineEventEntity.Companion.nextId(realm: Realm): Long {
|
|||
}
|
||||
|
||||
internal fun TimelineEventEntity.isMoreRecentThan(eventToCheck: TimelineEventEntity): Boolean {
|
||||
val currentChunk = this.chunk?.first() ?: return false
|
||||
val chunkToCheck = eventToCheck.chunk?.firstOrNull() ?: return false
|
||||
val currentChunk = this.chunk?.first(null) ?: return false
|
||||
val chunkToCheck = eventToCheck.chunk?.first(null) ?: return false
|
||||
return if (currentChunk == chunkToCheck) {
|
||||
this.displayIndex >= eventToCheck.displayIndex
|
||||
} else {
|
||||
|
|
|
@ -16,12 +16,15 @@
|
|||
|
||||
package org.matrix.android.sdk.internal.database.mapper
|
||||
|
||||
import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomEncryptionAlgorithm
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomJoinRules
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||
import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo
|
||||
import org.matrix.android.sdk.api.session.room.model.SpaceParentInfo
|
||||
import org.matrix.android.sdk.api.session.room.model.tag.RoomTag
|
||||
import org.matrix.android.sdk.api.session.typing.TypingUsersTracker
|
||||
import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM
|
||||
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity
|
||||
import org.matrix.android.sdk.internal.database.model.presence.toUserPresence
|
||||
import javax.inject.Inject
|
||||
|
@ -68,7 +71,9 @@ internal class RoomSummaryMapper @Inject constructor(private val timelineEventMa
|
|||
isEncrypted = roomSummaryEntity.isEncrypted,
|
||||
encryptionEventTs = roomSummaryEntity.encryptionEventTs,
|
||||
breadcrumbsIndex = roomSummaryEntity.breadcrumbsIndex,
|
||||
roomEncryptionTrustLevel = roomSummaryEntity.roomEncryptionTrustLevel,
|
||||
roomEncryptionTrustLevel = if (roomSummaryEntity.isEncrypted && roomSummaryEntity.e2eAlgorithm != MXCRYPTO_ALGORITHM_MEGOLM) {
|
||||
RoomEncryptionTrustLevel.E2EWithUnsupportedAlgorithm
|
||||
} else roomSummaryEntity.roomEncryptionTrustLevel,
|
||||
inviterId = roomSummaryEntity.inviterId,
|
||||
hasFailedSending = roomSummaryEntity.hasFailedSending,
|
||||
roomType = roomSummaryEntity.roomType,
|
||||
|
@ -99,7 +104,13 @@ internal class RoomSummaryMapper @Inject constructor(private val timelineEventMa
|
|||
worldReadable = it.childSummaryEntity?.joinRules == RoomJoinRules.PUBLIC
|
||||
)
|
||||
},
|
||||
flattenParentIds = roomSummaryEntity.flattenParentIds?.split("|") ?: emptyList()
|
||||
flattenParentIds = roomSummaryEntity.flattenParentIds?.split("|") ?: emptyList(),
|
||||
roomEncryptionAlgorithm = when (val alg = roomSummaryEntity.e2eAlgorithm) {
|
||||
// I should probably use #hasEncryptorClassForAlgorithm but it says it supports
|
||||
// OLM which is some legacy? Now only megolm allowed in rooms
|
||||
MXCRYPTO_ALGORITHM_MEGOLM -> RoomEncryptionAlgorithm.Megolm
|
||||
else -> RoomEncryptionAlgorithm.UnsupportedAlgorithm(alg)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -205,6 +205,11 @@ internal open class RoomSummaryEntity(
|
|||
if (value != field) field = value
|
||||
}
|
||||
|
||||
var e2eAlgorithm: String? = null
|
||||
set(value) {
|
||||
if (value != field) field = value
|
||||
}
|
||||
|
||||
var encryptionEventTs: Long? = 0
|
||||
set(value) {
|
||||
if (value != field) field = value
|
||||
|
|
|
@ -119,15 +119,15 @@ internal class DefaultRoom(override val roomId: String,
|
|||
}
|
||||
}
|
||||
|
||||
override suspend fun enableEncryption(algorithm: String) {
|
||||
override suspend fun enableEncryption(algorithm: String, force: Boolean) {
|
||||
when {
|
||||
isEncrypted() -> {
|
||||
(!force && isEncrypted() && encryptionAlgorithm() == MXCRYPTO_ALGORITHM_MEGOLM) -> {
|
||||
throw IllegalStateException("Encryption is already enabled for this room")
|
||||
}
|
||||
algorithm != MXCRYPTO_ALGORITHM_MEGOLM -> {
|
||||
(!force && algorithm != MXCRYPTO_ALGORITHM_MEGOLM) -> {
|
||||
throw InvalidParameterException("Only MXCRYPTO_ALGORITHM_MEGOLM algorithm is supported")
|
||||
}
|
||||
else -> {
|
||||
else -> {
|
||||
val params = SendStateTask.Params(
|
||||
roomId = roomId,
|
||||
stateKey = null,
|
||||
|
|
|
@ -51,7 +51,7 @@ internal class DefaultRoomGetter @Inject constructor(
|
|||
.equalTo(RoomSummaryEntityFields.IS_DIRECT, true)
|
||||
.equalTo(RoomSummaryEntityFields.MEMBERSHIP_STR, Membership.JOIN.name)
|
||||
.findAll()
|
||||
.firstOrNull { dm -> dm.otherMemberIds.size == 1 && dm.otherMemberIds.first() == otherUserId }
|
||||
.firstOrNull { dm -> dm.otherMemberIds.size == 1 && dm.otherMemberIds.first(null) == otherUserId }
|
||||
?.roomId
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,13 +38,11 @@ import org.matrix.android.sdk.api.session.room.send.SendState
|
|||
import org.matrix.android.sdk.api.session.sync.model.RoomSyncSummary
|
||||
import org.matrix.android.sdk.api.session.sync.model.RoomSyncUnreadNotifications
|
||||
import org.matrix.android.sdk.internal.crypto.EventDecryptor
|
||||
import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM
|
||||
import org.matrix.android.sdk.internal.crypto.crosssigning.DefaultCrossSigningService
|
||||
import org.matrix.android.sdk.internal.crypto.model.event.EncryptionEventContent
|
||||
import org.matrix.android.sdk.internal.database.mapper.ContentMapper
|
||||
import org.matrix.android.sdk.internal.database.mapper.asDomain
|
||||
import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntity
|
||||
import org.matrix.android.sdk.internal.database.model.EventEntity
|
||||
import org.matrix.android.sdk.internal.database.model.EventEntityFields
|
||||
import org.matrix.android.sdk.internal.database.model.GroupSummaryEntity
|
||||
import org.matrix.android.sdk.internal.database.model.RoomMemberSummaryEntityFields
|
||||
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity
|
||||
|
@ -57,7 +55,6 @@ import org.matrix.android.sdk.internal.database.query.getOrCreate
|
|||
import org.matrix.android.sdk.internal.database.query.getOrNull
|
||||
import org.matrix.android.sdk.internal.database.query.isEventRead
|
||||
import org.matrix.android.sdk.internal.database.query.where
|
||||
import org.matrix.android.sdk.internal.database.query.whereType
|
||||
import org.matrix.android.sdk.internal.di.UserId
|
||||
import org.matrix.android.sdk.internal.extensions.clearWith
|
||||
import org.matrix.android.sdk.internal.query.process
|
||||
|
@ -123,10 +120,8 @@ internal class RoomSummaryUpdater @Inject constructor(
|
|||
Timber.v("## Space: Updating summary room [$roomId] roomType: [$roomType]")
|
||||
|
||||
// Don't use current state for this one as we are only interested in having MXCRYPTO_ALGORITHM_MEGOLM event in the room
|
||||
val encryptionEvent = EventEntity.whereType(realm, roomId = roomId, type = EventType.STATE_ROOM_ENCRYPTION)
|
||||
.contains(EventEntityFields.CONTENT, "\"algorithm\":\"$MXCRYPTO_ALGORITHM_MEGOLM\"")
|
||||
.isNotNull(EventEntityFields.STATE_KEY)
|
||||
.findFirst()
|
||||
val encryptionEvent = CurrentStateEventEntity.getOrNull(realm, roomId, type = EventType.STATE_ROOM_ENCRYPTION, stateKey = "")?.root
|
||||
Timber.v("## CRYPTO: currentEncryptionEvent is $encryptionEvent")
|
||||
|
||||
val latestPreviewableEvent = RoomSummaryEventsHelper.getLatestPreviewableEvent(realm, roomId)
|
||||
|
||||
|
@ -152,6 +147,11 @@ internal class RoomSummaryUpdater @Inject constructor(
|
|||
.orEmpty()
|
||||
roomSummaryEntity.updateAliases(roomAliases)
|
||||
roomSummaryEntity.isEncrypted = encryptionEvent != null
|
||||
|
||||
roomSummaryEntity.e2eAlgorithm = ContentMapper.map(encryptionEvent?.content)
|
||||
?.toModel<EncryptionEventContent>()
|
||||
?.algorithm
|
||||
|
||||
roomSummaryEntity.encryptionEventTs = encryptionEvent?.originServerTs
|
||||
|
||||
if (roomSummaryEntity.membership == Membership.INVITE && inviterId != null) {
|
||||
|
|
|
@ -473,9 +473,9 @@ internal class TimelineChunk(private val chunkEntity: ChunkEntity,
|
|||
if (initialEventId != null) {
|
||||
frozenTimelineEvents.where().equalTo(TimelineEventEntityFields.EVENT_ID, initialEventId).findFirst()?.displayIndex
|
||||
} else if (direction == Timeline.Direction.BACKWARDS) {
|
||||
frozenTimelineEvents.first()?.displayIndex
|
||||
frozenTimelineEvents.first(null)?.displayIndex
|
||||
} else {
|
||||
frozenTimelineEvents.last()?.displayIndex
|
||||
frozenTimelineEvents.last(null)?.displayIndex
|
||||
}
|
||||
} else if (direction == Timeline.Direction.FORWARDS) {
|
||||
builtEvents.first().displayIndex + 1
|
||||
|
|
|
@ -224,6 +224,7 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle
|
|||
}
|
||||
val ageLocalTs = event.unsignedData?.age?.let { syncLocalTimestampMillis - it }
|
||||
val eventEntity = event.toEntity(roomId, SendState.SYNCED, ageLocalTs).copyToRealmOrIgnore(realm, insertType)
|
||||
Timber.v("## received state event ${event.type} and key ${event.stateKey}")
|
||||
CurrentStateEventEntity.getOrCreate(realm, roomId, event.stateKey, event.type).apply {
|
||||
// Timber.v("## Space state event: $eventEntity")
|
||||
eventId = event.eventId
|
||||
|
@ -399,6 +400,7 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle
|
|||
roomMemberEventHandler.handle(realm, roomEntity.roomId, event.stateKey, fixedContent, aggregator)
|
||||
}
|
||||
}
|
||||
|
||||
roomMemberContentsByUser.getOrPut(event.senderId) {
|
||||
// If we don't have any new state on this user, get it from db
|
||||
val rootStateEvent = CurrentStateEventEntity.getOrNull(realm, roomId, event.senderId, EventType.STATE_ROOM_MEMBER)?.root
|
||||
|
|
|
@ -15,7 +15,10 @@ kapt {
|
|||
// Note: 2 digits max for each value
|
||||
ext.versionMajor = 1
|
||||
ext.versionMinor = 3
|
||||
ext.versionPatch = 13
|
||||
// Note: even values are reserved for regular release, odd values for hotfix release.
|
||||
// When creating a hotfix, you should decrease the value, since the current value
|
||||
// is the value for the next regular release.
|
||||
ext.versionPatch = 16
|
||||
|
||||
static def getGitTimestamp() {
|
||||
def cmd = 'git show -s --format=%ct'
|
||||
|
@ -207,7 +210,6 @@ android {
|
|||
// Comment to run on Android 12
|
||||
// execution 'ANDROIDX_TEST_ORCHESTRATOR'
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
debug {
|
||||
keyAlias 'androiddebugkey'
|
||||
|
@ -215,6 +217,12 @@ android {
|
|||
storeFile file('./signature/debug.keystore')
|
||||
storePassword 'android'
|
||||
}
|
||||
release {
|
||||
keyAlias project.property("signing.element.keyId")
|
||||
keyPassword project.property("signing.element.keyPassword")
|
||||
storeFile file(project.property("signing.element.storePath"))
|
||||
storePassword project.property("signing.element.storePassword")
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
|
@ -245,6 +253,7 @@ android {
|
|||
optimizeCode true
|
||||
proguardFiles 'proguard-rules.pro'
|
||||
}
|
||||
signingConfig signingConfigs.release
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -362,7 +371,7 @@ dependencies {
|
|||
implementation 'com.facebook.stetho:stetho:1.6.0'
|
||||
|
||||
// Phone number https://github.com/google/libphonenumber
|
||||
implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.40'
|
||||
implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.41'
|
||||
|
||||
// FlowBinding
|
||||
implementation libs.github.flowBinding
|
||||
|
|
|
@ -154,8 +154,6 @@ class SecurityBootstrapTest : VerificationTestBase() {
|
|||
onView(withId(R.id.recoveryCopy))
|
||||
.perform(click())
|
||||
|
||||
Thread.sleep(1000)
|
||||
|
||||
// Dismiss dialog
|
||||
onView(withText(R.string.ok)).inRoot(RootMatchers.isDialog()).perform(click())
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ import im.vector.app.R
|
|||
import im.vector.app.core.epoxy.ClickListener
|
||||
import im.vector.app.core.epoxy.VectorEpoxyHolder
|
||||
import im.vector.app.core.epoxy.VectorEpoxyModel
|
||||
import im.vector.app.core.epoxy.charsequence.EpoxyCharSequence
|
||||
import im.vector.app.core.epoxy.onClick
|
||||
import im.vector.app.core.extensions.setTextOrHide
|
||||
import im.vector.app.features.themes.ThemeUtils
|
||||
|
@ -38,7 +39,7 @@ import im.vector.app.features.themes.ThemeUtils
|
|||
abstract class GenericFooterItem : VectorEpoxyModel<GenericFooterItem.Holder>() {
|
||||
|
||||
@EpoxyAttribute
|
||||
var text: String? = null
|
||||
var text: EpoxyCharSequence? = null
|
||||
|
||||
@EpoxyAttribute
|
||||
var style: ItemStyle = ItemStyle.NORMAL_TEXT
|
||||
|
@ -56,7 +57,7 @@ abstract class GenericFooterItem : VectorEpoxyModel<GenericFooterItem.Holder>()
|
|||
override fun bind(holder: Holder) {
|
||||
super.bind(holder)
|
||||
|
||||
holder.text.setTextOrHide(text)
|
||||
holder.text.setTextOrHide(text?.charSequence)
|
||||
holder.text.typeface = style.toTypeFace()
|
||||
holder.text.textSize = style.toTextSize()
|
||||
holder.text.gravity = if (centered) Gravity.CENTER_HORIZONTAL else Gravity.START
|
||||
|
|
|
@ -25,6 +25,7 @@ import android.widget.LinearLayout
|
|||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.text.italic
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.epoxy.onClick
|
||||
import im.vector.app.core.error.ResourceLimitErrorFormatter
|
||||
import im.vector.app.core.extensions.exhaustive
|
||||
import im.vector.app.core.utils.DimensionConverter
|
||||
|
@ -73,6 +74,7 @@ class NotificationAreaView @JvmOverloads constructor(
|
|||
is State.Default -> renderDefault()
|
||||
is State.Hidden -> renderHidden()
|
||||
is State.NoPermissionToPost -> renderNoPermissionToPost()
|
||||
is State.UnsupportedAlgorithm -> renderUnsupportedAlgorithm(newState)
|
||||
is State.Tombstone -> renderTombstone()
|
||||
is State.ResourceLimitExceededError -> renderResourceLimitExceededError(newState)
|
||||
}.exhaustive
|
||||
|
@ -106,6 +108,24 @@ class NotificationAreaView @JvmOverloads constructor(
|
|||
views.roomNotificationMessage.setTextColor(ThemeUtils.getColor(context, R.attr.vctr_content_secondary))
|
||||
}
|
||||
|
||||
private fun renderUnsupportedAlgorithm(e2eState: State.UnsupportedAlgorithm) {
|
||||
visibility = View.VISIBLE
|
||||
views.roomNotificationIcon.setImageResource(R.drawable.ic_warning_badge)
|
||||
val text = if (e2eState.canRestore) {
|
||||
R.string.room_unsupported_e2e_algorithm_as_admin
|
||||
} else R.string.room_unsupported_e2e_algorithm
|
||||
val message = span {
|
||||
italic {
|
||||
+resources.getString(text)
|
||||
}
|
||||
}
|
||||
views.roomNotificationMessage.onClick {
|
||||
delegate?.onMisconfiguredEncryptionClicked()
|
||||
}
|
||||
views.roomNotificationMessage.text = message
|
||||
views.roomNotificationMessage.setTextColor(ThemeUtils.getColor(context, R.attr.vctr_content_secondary))
|
||||
}
|
||||
|
||||
private fun renderResourceLimitExceededError(state: State.ResourceLimitExceededError) {
|
||||
visibility = View.VISIBLE
|
||||
val resourceLimitErrorFormatter = ResourceLimitErrorFormatter(context)
|
||||
|
@ -163,6 +183,7 @@ class NotificationAreaView @JvmOverloads constructor(
|
|||
|
||||
// User can't post messages to room because his power level doesn't allow it.
|
||||
object NoPermissionToPost : State()
|
||||
data class UnsupportedAlgorithm(val canRestore: Boolean) : State()
|
||||
|
||||
// View will be Gone
|
||||
object Hidden : State()
|
||||
|
@ -179,5 +200,6 @@ class NotificationAreaView @JvmOverloads constructor(
|
|||
*/
|
||||
interface Delegate {
|
||||
fun onTombstoneEventClicked()
|
||||
fun onMisconfiguredEncryptionClicked()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,6 +61,10 @@ class ShieldImageView @JvmOverloads constructor(
|
|||
else R.drawable.ic_shield_trusted
|
||||
)
|
||||
}
|
||||
RoomEncryptionTrustLevel.E2EWithUnsupportedAlgorithm -> {
|
||||
contentDescription = context.getString(R.string.a11y_trust_level_trusted)
|
||||
setImageResource(R.drawable.ic_warning_badge)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -71,5 +75,6 @@ fun RoomEncryptionTrustLevel.toDrawableRes(): Int {
|
|||
RoomEncryptionTrustLevel.Default -> R.drawable.ic_shield_black
|
||||
RoomEncryptionTrustLevel.Warning -> R.drawable.ic_shield_warning
|
||||
RoomEncryptionTrustLevel.Trusted -> R.drawable.ic_shield_trusted
|
||||
RoomEncryptionTrustLevel.E2EWithUnsupportedAlgorithm -> R.drawable.ic_warning_badge
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ package im.vector.app.features.devtools
|
|||
|
||||
import com.airbnb.epoxy.TypedEpoxyController
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.epoxy.charsequence.toEpoxyCharSequence
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import im.vector.app.core.ui.list.genericFooterItem
|
||||
import im.vector.app.features.form.formEditTextItem
|
||||
|
@ -36,7 +37,7 @@ class RoomDevToolSendFormController @Inject constructor(
|
|||
|
||||
genericFooterItem {
|
||||
id("topSpace")
|
||||
text("")
|
||||
text("".toEpoxyCharSequence())
|
||||
}
|
||||
formEditTextItem {
|
||||
id("event_type")
|
||||
|
|
|
@ -42,6 +42,7 @@ sealed class RoomDetailAction : VectorViewModelAction {
|
|||
object MarkAllAsRead : RoomDetailAction()
|
||||
data class DownloadOrOpen(val eventId: String, val senderId: String?, val messageFileContent: MessageWithAttachmentContent) : RoomDetailAction()
|
||||
object JoinAndOpenReplacementRoom : RoomDetailAction()
|
||||
object OnClickMisconfiguredEncryption : RoomDetailAction()
|
||||
object AcceptInvite : RoomDetailAction()
|
||||
object RejectInvite : RoomDetailAction()
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@ sealed class RoomDetailViewEvents : VectorViewEvents {
|
|||
object OpenInvitePeople : RoomDetailViewEvents()
|
||||
object OpenSetRoomAvatarDialog : RoomDetailViewEvents()
|
||||
object OpenRoomSettings : RoomDetailViewEvents()
|
||||
object OpenRoomProfile : RoomDetailViewEvents()
|
||||
data class ShowRoomAvatarFullScreen(val matrixItem: MatrixItem?, val view: View?) : RoomDetailViewEvents()
|
||||
|
||||
object ShowWaitingView : RoomDetailViewEvents()
|
||||
|
|
|
@ -226,11 +226,13 @@ class RoomDetailViewModel @AssistedInject constructor(
|
|||
val canInvite = PowerLevelsHelper(it).isUserAbleToInvite(session.myUserId)
|
||||
val isAllowedToManageWidgets = session.widgetService().hasPermissionsToHandleWidgets(room.roomId)
|
||||
val isAllowedToStartWebRTCCall = PowerLevelsHelper(it).isUserAllowedToSend(session.myUserId, false, EventType.CALL_INVITE)
|
||||
val isAllowedToSetupEncryption = PowerLevelsHelper(it).isUserAllowedToSend(session.myUserId, true, EventType.STATE_ROOM_ENCRYPTION)
|
||||
setState {
|
||||
copy(
|
||||
canInvite = canInvite,
|
||||
isAllowedToManageWidgets = isAllowedToManageWidgets,
|
||||
isAllowedToStartWebRTCCall = isAllowedToStartWebRTCCall
|
||||
isAllowedToStartWebRTCCall = isAllowedToStartWebRTCCall,
|
||||
isAllowedToSetupEncryption = isAllowedToSetupEncryption
|
||||
)
|
||||
}
|
||||
}.launchIn(viewModelScope)
|
||||
|
@ -355,6 +357,7 @@ class RoomDetailViewModel @AssistedInject constructor(
|
|||
is RoomDetailAction.DownloadOrOpen -> handleOpenOrDownloadFile(action)
|
||||
is RoomDetailAction.NavigateToEvent -> handleNavigateToEvent(action)
|
||||
is RoomDetailAction.JoinAndOpenReplacementRoom -> handleJoinAndOpenReplacementRoom()
|
||||
is RoomDetailAction.OnClickMisconfiguredEncryption -> handleClickMisconfiguredE2E()
|
||||
is RoomDetailAction.ResendMessage -> handleResendEvent(action)
|
||||
is RoomDetailAction.RemoveFailedEcho -> handleRemove(action)
|
||||
is RoomDetailAction.MarkAllAsRead -> handleMarkAllAsRead()
|
||||
|
@ -663,6 +666,12 @@ class RoomDetailViewModel @AssistedInject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun handleClickMisconfiguredE2E() = withState { state ->
|
||||
if (state.isAllowedToSetupEncryption) {
|
||||
_viewEvents.post(RoomDetailViewEvents.OpenRoomProfile)
|
||||
}
|
||||
}
|
||||
|
||||
private fun isIntegrationEnabled() = session.integrationManagerService().isIntegrationEnabled()
|
||||
|
||||
fun isMenuItemVisible(@IdRes itemId: Int): Boolean = com.airbnb.mvrx.withState(this) { state ->
|
||||
|
|
|
@ -66,6 +66,7 @@ data class RoomDetailViewState(
|
|||
val canInvite: Boolean = true,
|
||||
val isAllowedToManageWidgets: Boolean = false,
|
||||
val isAllowedToStartWebRTCCall: Boolean = true,
|
||||
val isAllowedToSetupEncryption: Boolean = true,
|
||||
val hasFailedSending: Boolean = false,
|
||||
val jitsiState: JitsiState = JitsiState(),
|
||||
val rootThreadEventId: String? = null,
|
||||
|
|
|
@ -136,12 +136,14 @@ import im.vector.app.features.crypto.keysbackup.restore.KeysBackupRestoreActivit
|
|||
import im.vector.app.features.crypto.verification.VerificationBottomSheet
|
||||
import im.vector.app.features.home.AvatarRenderer
|
||||
import im.vector.app.features.home.room.detail.arguments.TimelineArgs
|
||||
import im.vector.app.features.home.room.detail.composer.CanSendStatus
|
||||
import im.vector.app.features.home.room.detail.composer.MessageComposerAction
|
||||
import im.vector.app.features.home.room.detail.composer.MessageComposerView
|
||||
import im.vector.app.features.home.room.detail.composer.MessageComposerViewEvents
|
||||
import im.vector.app.features.home.room.detail.composer.MessageComposerViewModel
|
||||
import im.vector.app.features.home.room.detail.composer.MessageComposerViewState
|
||||
import im.vector.app.features.home.room.detail.composer.SendMode
|
||||
import im.vector.app.features.home.room.detail.composer.boolean
|
||||
import im.vector.app.features.home.room.detail.composer.voice.VoiceMessageRecorderView
|
||||
import im.vector.app.features.home.room.detail.composer.voice.VoiceMessageRecorderView.RecordingUiState
|
||||
import im.vector.app.features.home.room.detail.readreceipts.DisplayReadReceiptsBottomSheet
|
||||
|
@ -391,7 +393,7 @@ class TimelineFragment @Inject constructor(
|
|||
}
|
||||
|
||||
messageComposerViewModel.onEach(MessageComposerViewState::sendMode, MessageComposerViewState::canSendMessage) { mode, canSend ->
|
||||
if (!canSend) {
|
||||
if (!canSend.boolean()) {
|
||||
return@onEach
|
||||
}
|
||||
when (mode) {
|
||||
|
@ -458,7 +460,8 @@ class TimelineFragment @Inject constructor(
|
|||
is RoomDetailViewEvents.OpenRoom -> handleOpenRoom(it)
|
||||
RoomDetailViewEvents.OpenInvitePeople -> navigator.openInviteUsersToRoom(requireContext(), timelineArgs.roomId)
|
||||
RoomDetailViewEvents.OpenSetRoomAvatarDialog -> galleryOrCameraDialogHelper.show()
|
||||
RoomDetailViewEvents.OpenRoomSettings -> handleOpenRoomSettings()
|
||||
RoomDetailViewEvents.OpenRoomSettings -> handleOpenRoomSettings(RoomProfileActivity.EXTRA_DIRECT_ACCESS_ROOM_SETTINGS)
|
||||
RoomDetailViewEvents.OpenRoomProfile -> handleOpenRoomSettings()
|
||||
is RoomDetailViewEvents.ShowRoomAvatarFullScreen -> it.matrixItem?.let { item ->
|
||||
navigator.openBigImageViewer(requireActivity(), it.view, item)
|
||||
}
|
||||
|
@ -582,11 +585,11 @@ class TimelineFragment @Inject constructor(
|
|||
)
|
||||
}
|
||||
|
||||
private fun handleOpenRoomSettings() {
|
||||
private fun handleOpenRoomSettings(directAccess: Int? = null) {
|
||||
navigator.openRoomProfile(
|
||||
requireContext(),
|
||||
timelineArgs.roomId,
|
||||
RoomProfileActivity.EXTRA_DIRECT_ACCESS_ROOM_SETTINGS
|
||||
roomDetailArgs.roomId,
|
||||
directAccess
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -951,6 +954,10 @@ class TimelineFragment @Inject constructor(
|
|||
override fun onTombstoneEventClicked() {
|
||||
roomDetailViewModel.handle(RoomDetailAction.JoinAndOpenReplacementRoom)
|
||||
}
|
||||
|
||||
override fun onMisconfiguredEncryptionClicked() {
|
||||
roomDetailViewModel.handle(RoomDetailAction.OnClickMisconfiguredEncryption)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1348,7 +1355,7 @@ class TimelineFragment @Inject constructor(
|
|||
val canSendMessage = withState(messageComposerViewModel) {
|
||||
it.canSendMessage
|
||||
}
|
||||
if (!canSendMessage) {
|
||||
if (!canSendMessage.boolean()) {
|
||||
return false
|
||||
}
|
||||
return when (model) {
|
||||
|
@ -1530,10 +1537,18 @@ class TimelineFragment @Inject constructor(
|
|||
views.voiceMessageRecorderView.render(messageComposerState.voiceRecordingUiState)
|
||||
views.composerLayout.setRoomEncrypted(summary.isEncrypted)
|
||||
// views.composerLayout.alwaysShowSendButton = false
|
||||
if (messageComposerState.canSendMessage) {
|
||||
views.notificationAreaView.render(NotificationAreaView.State.Hidden)
|
||||
} else {
|
||||
views.notificationAreaView.render(NotificationAreaView.State.NoPermissionToPost)
|
||||
when (messageComposerState.canSendMessage) {
|
||||
CanSendStatus.Allowed -> {
|
||||
NotificationAreaView.State.Hidden
|
||||
}
|
||||
CanSendStatus.NoPermission -> {
|
||||
NotificationAreaView.State.NoPermissionToPost
|
||||
}
|
||||
is CanSendStatus.UnSupportedE2eAlgorithm -> {
|
||||
NotificationAreaView.State.UnsupportedAlgorithm(mainState.isAllowedToSetupEncryption)
|
||||
}
|
||||
}.let {
|
||||
views.notificationAreaView.render(it)
|
||||
}
|
||||
} else {
|
||||
views.hideComposerViews()
|
||||
|
|
|
@ -38,6 +38,7 @@ import im.vector.app.features.session.coroutineScope
|
|||
import im.vector.app.features.settings.VectorPreferences
|
||||
import im.vector.app.features.voice.VoicePlayerHelper
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.launch
|
||||
import org.matrix.android.sdk.api.query.QueryStringValue
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
|
@ -47,6 +48,7 @@ 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.RoomAvatarContent
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomEncryptionAlgorithm
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomMemberContent
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageType
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
|
||||
|
@ -55,6 +57,8 @@ import org.matrix.android.sdk.api.session.room.timeline.getLastMessageContent
|
|||
import org.matrix.android.sdk.api.session.room.timeline.getRelationContent
|
||||
import org.matrix.android.sdk.api.session.room.timeline.getTextEditableContent
|
||||
import org.matrix.android.sdk.api.session.space.CreateSpaceParams
|
||||
import org.matrix.android.sdk.flow.flow
|
||||
import org.matrix.android.sdk.flow.unwrap
|
||||
import timber.log.Timber
|
||||
|
||||
class MessageComposerViewModel @AssistedInject constructor(
|
||||
|
@ -74,7 +78,7 @@ class MessageComposerViewModel @AssistedInject constructor(
|
|||
|
||||
init {
|
||||
loadDraftIfAny()
|
||||
observePowerLevel()
|
||||
observePowerLevelAndEncryption()
|
||||
subscribeToStateInternal()
|
||||
}
|
||||
|
||||
|
@ -137,12 +141,30 @@ class MessageComposerViewModel @AssistedInject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun observePowerLevel() {
|
||||
PowerLevelsFlowFactory(room).createFlow()
|
||||
.setOnEach {
|
||||
val canSendMessage = PowerLevelsHelper(it).isUserAllowedToSend(session.myUserId, false, EventType.MESSAGE)
|
||||
copy(canSendMessage = canSendMessage)
|
||||
private fun observePowerLevelAndEncryption() {
|
||||
combine(
|
||||
PowerLevelsFlowFactory(room).createFlow(),
|
||||
room.flow().liveRoomSummary().unwrap()
|
||||
) { pl, sum ->
|
||||
val canSendMessage = PowerLevelsHelper(pl).isUserAllowedToSend(session.myUserId, false, EventType.MESSAGE)
|
||||
if (canSendMessage) {
|
||||
val isE2E = sum.isEncrypted
|
||||
if (isE2E) {
|
||||
val roomEncryptionAlgorithm = sum.roomEncryptionAlgorithm
|
||||
if (roomEncryptionAlgorithm is RoomEncryptionAlgorithm.UnsupportedAlgorithm) {
|
||||
CanSendStatus.UnSupportedE2eAlgorithm(roomEncryptionAlgorithm.name)
|
||||
} else {
|
||||
CanSendStatus.Allowed
|
||||
}
|
||||
} else {
|
||||
CanSendStatus.Allowed
|
||||
}
|
||||
} else {
|
||||
CanSendStatus.NoPermission
|
||||
}
|
||||
}.setOnEach {
|
||||
copy(canSendMessage = it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleEnterQuoteMode(action: MessageComposerAction.EnterQuoteMode) {
|
||||
|
|
|
@ -43,9 +43,23 @@ sealed interface SendMode {
|
|||
data class Voice(val text: String) : SendMode
|
||||
}
|
||||
|
||||
sealed interface CanSendStatus {
|
||||
object Allowed : CanSendStatus
|
||||
object NoPermission : CanSendStatus
|
||||
data class UnSupportedE2eAlgorithm(val algorithm: String?) : CanSendStatus
|
||||
}
|
||||
|
||||
fun CanSendStatus.boolean(): Boolean {
|
||||
return when (this) {
|
||||
CanSendStatus.Allowed -> true
|
||||
CanSendStatus.NoPermission -> false
|
||||
is CanSendStatus.UnSupportedE2eAlgorithm -> false
|
||||
}
|
||||
}
|
||||
|
||||
data class MessageComposerViewState(
|
||||
val roomId: String,
|
||||
val canSendMessage: Boolean = true,
|
||||
val canSendMessage: CanSendStatus = CanSendStatus.Allowed,
|
||||
val isSendButtonVisible: Boolean = false,
|
||||
val rootThreadEventId: String? = null,
|
||||
val sendMode: SendMode = SendMode.Regular("", false),
|
||||
|
@ -60,8 +74,9 @@ data class MessageComposerViewState(
|
|||
}
|
||||
|
||||
val isVoiceMessageIdle = !isVoiceRecording
|
||||
val isComposerVisible = canSendMessage && !isVoiceRecording
|
||||
val isVoiceMessageRecorderVisible = canSendMessage && !isSendButtonVisible
|
||||
|
||||
val isComposerVisible = canSendMessage.boolean() && !isVoiceRecording
|
||||
val isVoiceMessageRecorderVisible = canSendMessage.boolean() && !isSendButtonVisible
|
||||
|
||||
constructor(args: TimelineArgs) : this(
|
||||
roomId = args.roomId,
|
||||
|
|
|
@ -62,7 +62,7 @@ class ViewEditHistoryEpoxyController @Inject constructor(
|
|||
is Fail -> {
|
||||
genericFooterItem {
|
||||
id("failure")
|
||||
text(host.stringProvider.getString(R.string.unknown_error))
|
||||
text(host.stringProvider.getString(R.string.unknown_error).toEpoxyCharSequence())
|
||||
}
|
||||
}
|
||||
is Success -> {
|
||||
|
|
|
@ -63,9 +63,9 @@ class EncryptionItemFactory @Inject constructor(
|
|||
)
|
||||
shield = StatusTileTimelineItem.ShieldUIState.BLACK
|
||||
} else {
|
||||
title = stringProvider.getString(R.string.encryption_not_enabled)
|
||||
title = stringProvider.getString(R.string.encryption_misconfigured)
|
||||
description = stringProvider.getString(R.string.encryption_unknown_algorithm_tile_description)
|
||||
shield = StatusTileTimelineItem.ShieldUIState.RED
|
||||
shield = StatusTileTimelineItem.ShieldUIState.ERROR
|
||||
}
|
||||
return StatusTileTimelineItem_()
|
||||
.attributes(
|
||||
|
|
|
@ -57,6 +57,7 @@ abstract class StatusTileTimelineItem : AbsBaseMessageItem<StatusTileTimelineIte
|
|||
ShieldUIState.GREEN -> R.drawable.ic_shield_trusted
|
||||
ShieldUIState.BLACK -> R.drawable.ic_shield_black
|
||||
ShieldUIState.RED -> R.drawable.ic_shield_warning
|
||||
ShieldUIState.ERROR -> R.drawable.ic_warning_badge
|
||||
}
|
||||
|
||||
holder.titleView.setCompoundDrawablesWithIntrinsicBounds(
|
||||
|
@ -98,6 +99,7 @@ abstract class StatusTileTimelineItem : AbsBaseMessageItem<StatusTileTimelineIte
|
|||
enum class ShieldUIState {
|
||||
BLACK,
|
||||
RED,
|
||||
GREEN
|
||||
GREEN,
|
||||
ERROR
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ class ViewReactionsEpoxyController @Inject constructor(
|
|||
is Fail -> {
|
||||
genericFooterItem {
|
||||
id("failure")
|
||||
text(host.stringProvider.getString(R.string.unknown_error))
|
||||
text(host.stringProvider.getString(R.string.unknown_error).toEpoxyCharSequence())
|
||||
}
|
||||
}
|
||||
is Success -> {
|
||||
|
|
|
@ -18,6 +18,7 @@ package im.vector.app.features.home.room.detail.widget
|
|||
|
||||
import com.airbnb.epoxy.TypedEpoxyController
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.epoxy.charsequence.toEpoxyCharSequence
|
||||
import im.vector.app.core.resources.ColorProvider
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import im.vector.app.core.ui.list.genericButtonItem
|
||||
|
@ -40,7 +41,7 @@ class RoomWidgetsController @Inject constructor(
|
|||
if (widgets.isEmpty()) {
|
||||
genericFooterItem {
|
||||
id("empty")
|
||||
text(host.stringProvider.getString(R.string.room_no_active_widgets))
|
||||
text(host.stringProvider.getString(R.string.room_no_active_widgets).toEpoxyCharSequence())
|
||||
}
|
||||
} else {
|
||||
widgets.forEach { widget ->
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue