Merge branch 'develop' of github.com:vector-im/element-android into feature/dla/fix_reply_and_quote_newlines

This commit is contained in:
David Langley 2021-12-14 13:46:45 +00:00
commit 20b5742227
727 changed files with 9855 additions and 4589 deletions

View File

@ -70,4 +70,27 @@ jobs:
body: |
- Update SAS Strings from matrix-doc.
branch: sync-sas-strings
base: develop
sync-analytics-plan:
runs-on: ubuntu-latest
# Skip in forks
if: github.repository == 'vector-im/element-android'
steps:
- uses: actions/checkout@v2
- name: Run analytics import script
run: ./tools/import_analytic_plan.sh
- name: Create Pull Request for analytics plan
uses: peter-evans/create-pull-request@v3
with:
commit-message: Sync analytics plan
title: Sync analytics plan
body: |
### Update analytics plan
Reviewers:
- [ ] Please remove usage of Event or Enum which may have been removed or updated
- [ ] please ensure new Events or new Enums are used to send analytics by pushing new commit(s) to this PR.
*Note*: Change are coming from [this project](https://github.com/matrix-org/matrix-analytics-events)
branch: sync-analytics-plan
base: develop

View File

@ -6,7 +6,7 @@ on:
jobs:
move_needs_info_issues:
name: Move X-Needs-Info issues to Need info on triage board
name: X-Needs-Info issues to Need info column on triage board
runs-on: ubuntu-latest
steps:
- uses: konradpabjan/move-labeled-or-milestoned-issue@219d384e03fa4b6460cd24f9f37d19eb033a4338
@ -17,22 +17,24 @@ jobs:
label-name: "X-Needs-Info"
add_priority_design_issues_to_project:
name: Move priority X-Needs-Design issues to Design project board
name: P1 X-Needs-Design to Design project board
runs-on: ubuntu-latest
if: >
contains(github.event.issue.labels.*.name, 'X-Needs-Design') &&
(contains(github.event.issue.labels.*.name, 'O-Frequent') ||
contains(github.event.issue.labels.*.name, 'O-Occasional')) &&
(contains(github.event.issue.labels.*.name, 'S-Critical') ||
contains(github.event.issue.labels.*.name, 'S-Major') ||
contains(github.event.issue.labels.*.name, 'S-Minor'))
(contains(github.event.issue.labels.*.name, 'S-Critical') &&
(contains(github.event.issue.labels.*.name, 'O-Frequent') ||
contains(github.event.issue.labels.*.name, 'O-Occasional')) ||
contains(github.event.issue.labels.*.name, 'S-Major') &&
contains(github.event.issue.labels.*.name, 'O-Frequent') ||
contains(github.event.issue.labels.*.name, 'A11y') &&
contains(github.event.issue.labels.*.name, 'O-Frequent'))
steps:
- uses: octokit/graphql-action@v2.x
id: add_to_project
with:
headers: '{"GraphQL-Features": "projects_next_graphql"}'
query: |
mutation add_to_project($projectid:String!,$contentid:String!) {
mutation add_to_project($projectid:ID!,$contentid:ID!) {
addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) {
projectNextItem {
id
@ -45,40 +47,33 @@ jobs:
PROJECT_ID: "PN_kwDOAM0swc0sUA"
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
move_spaces_issues:
name: Move Spaces issues to Delight project board
runs-on: ubuntu-latest
if: >
contains(github.event.issue.labels.*.name, 'A-Spaces') ||
contains(github.event.issue.labels.*.name, 'A-Space-Settings') ||
contains(github.event.issue.labels.*.name, 'A-Subspaces')
steps:
- uses: konradpabjan/move-labeled-or-milestoned-issue@219d384e03fa4b6460cd24f9f37d19eb033a4338
with:
action-token: "${{ secrets.ELEMENT_BOT_TOKEN }}"
project-url: "https://github.com/orgs/vector-im/projects/6"
column-name: "📥 Inbox"
label-name: "A-Spaces"
- uses: octokit/graphql-action@v2.x
id: add_to_delight2
with:
headers: '{"GraphQL-Features": "projects_next_graphql"}'
query: |
mutation add_to_project($projectid:String!,$contentid:String!) {
addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) {
projectNextItem {
id
}
}
}
projectid: ${{ env.PROJECT_ID }}
contentid: ${{ github.event.issue.node_id }}
env:
PROJECT_ID: "PN_kwDOAM0swc1HvQ"
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
# delight_issues_to_board:
# name: Spaces issues to new Delight project board
# runs-on: ubuntu-latest
# if: >
# contains(github.event.issue.labels.*.name, 'A-Spaces') ||
# contains(github.event.issue.labels.*.name, 'A-Space-Settings') ||
# contains(github.event.issue.labels.*.name, 'A-Subspaces')
# steps:
# - uses: octokit/graphql-action@v2.x
# with:
# headers: '{"GraphQL-Features": "projects_next_graphql"}'
# query: |
# mutation add_to_project($projectid:ID!,$contentid:ID!) {
# addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) {
# projectNextItem {
# id
# }
# }
# }
# projectid: ${{ env.PROJECT_ID }}
# contentid: ${{ github.event.issue.node_id }}
# env:
# PROJECT_ID: "PN_kwDOAM0swc1HvQ"
# GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
move_voice-message_issues:
name: Move A-Voice Messages to Voice message board
name: A-Voice Messages to voice message board
runs-on: ubuntu-latest
if: >
contains(github.event.issue.labels.*.name, 'A-Voice Messages')
@ -87,7 +82,7 @@ jobs:
with:
headers: '{"GraphQL-Features": "projects_next_graphql"}'
query: |
mutation add_to_project($projectid:String!,$contentid:String!) {
mutation add_to_project($projectid:ID!,$contentid:ID!) {
addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) {
projectNextItem {
id
@ -101,7 +96,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
move_threads_issues:
name: Move A-Threads to Thread board
name: A-Threads to Thread board
runs-on: ubuntu-latest
if: >
contains(github.event.issue.labels.*.name, 'A-Threads')
@ -110,7 +105,7 @@ jobs:
with:
headers: '{"GraphQL-Features": "projects_next_graphql"}'
query: |
mutation add_to_project($projectid:String!,$contentid:String!) {
mutation add_to_project($projectid:ID!,$contentid:ID!) {
addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) {
projectNextItem {
id
@ -122,3 +117,26 @@ jobs:
env:
PROJECT_ID: "PN_kwDOAM0swc0rRA"
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
move_message_bubbles_issues:
name: A-Message-Bubbles to Message bubbles board
runs-on: ubuntu-latest
if: >
contains(github.event.issue.labels.*.name, 'A-Message-Bubbles')
steps:
- uses: octokit/graphql-action@v2.x
with:
headers: '{"GraphQL-Features": "projects_next_graphql"}'
query: |
mutation add_to_project($projectid:ID!,$contentid:ID!) {
addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) {
projectNextItem {
id
}
}
}
projectid: ${{ env.PROJECT_ID }}
contentid: ${{ github.event.issue.node_id }}
env:
PROJECT_ID: "PN_kwDOAM0swc3m-g"
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}

View File

@ -1,4 +1,4 @@
name: Move P1 issues into the P1 column for the App Team and Crypto team
name: Move P1 bugs to boards
on:
issues:

View File

@ -24,6 +24,7 @@
<w>pbkdf</w>
<w>pids</w>
<w>pkcs</w>
<w>posthog</w>
<w>previewable</w>
<w>previewables</w>
<w>pstn</w>

View File

@ -1,3 +1,35 @@
Changes in Element v1.3.9 (2021-12-01)
======================================
Features ✨
----------
- Voice messages: Persist drafts of voice messages when navigating between rooms ([#3922](https://github.com/vector-im/element-android/issues/3922))
- Make Element Android Thread aware ([#4246](https://github.com/vector-im/element-android/issues/4246))
- Iterate on the consent dialog of the identity server. ([#4577](https://github.com/vector-im/element-android/issues/4577))
Bugfixes 🐛
----------
- Fixes left over text when inserting emojis via the ':' menu and replaces the last typed ':' rather than the one at the end of the message ([#3449](https://github.com/vector-im/element-android/issues/3449))
- Fixing queued voice message failing to send or retry ([#3833](https://github.com/vector-im/element-android/issues/3833))
- Keeping device screen on whilst recording and playing back voice messages ([#4022](https://github.com/vector-im/element-android/issues/4022))
- Allow voice messages to continue recording during device rotation ([#4067](https://github.com/vector-im/element-android/issues/4067))
- Allowing users to hang up VOIP calls during the initialisation phase (avoids getting stuck in the call screen if something goes wrong) ([#4144](https://github.com/vector-im/element-android/issues/4144))
- Make the verification shields the same in Element Web and Element Android ([#4338](https://github.com/vector-im/element-android/issues/4338))
- Fix a display issue in the composer when the replied message is changed. ([#4343](https://github.com/vector-im/element-android/issues/4343))
- Dismissing the Fdroid variant Listening for notifications on sign out, fixes crash when tapping the notification when signed out ([#4488](https://github.com/vector-im/element-android/issues/4488))
- Fix a crash when displaying the bootstrap bottom sheet ([#4520](https://github.com/vector-im/element-android/issues/4520))
- Remove duplicated settings declaration ([#4539](https://github.com/vector-im/element-android/issues/4539))
- Fixes .ogg files failing to upload to rooms ([#4552](https://github.com/vector-im/element-android/issues/4552))
- Add robustness when getting data from cursors ([#4605](https://github.com/vector-im/element-android/issues/4605))
Other changes
-------------
- Upgrade Jitsi lib (and so webrtc) from Jitsi android-sdk-3.1.0 to android-sdk-3.10.0 ([#4504](https://github.com/vector-im/element-android/issues/4504))
- Improve crypto logs to help debug decryption failures ([#4507](https://github.com/vector-im/element-android/issues/4507))
- Voice recording mic button refactor with small animation tweaks in preparation for voice drafts ([#4515](https://github.com/vector-im/element-android/issues/4515))
- Remove requestModelBuild() from epoxy Controllers init{} block ([#4591](https://github.com/vector-im/element-android/issues/4591))
Changes in Element v1.3.8 (2021-11-17)
======================================

View File

@ -1,12 +1,11 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
apply from: 'dependencies.gradle'
apply from: 'dependencies_groups.gradle'
repositories {
google()
jcenter()
maven {
url "https://plugins.gradle.org/m2/"
}
@ -37,45 +36,50 @@ allprojects {
apply plugin: "org.jlleitschuh.gradle.ktlint"
repositories {
// For olm library. This has to be declared first, to ensure that Olm library is not downloaded from another repo
// For olm library.
maven {
url 'https://gitlab.matrix.org/api/v4/projects/27/packages/maven'
content {
groups.olm.regex.each { includeGroupByRegex it }
groups.olm.group.each { includeGroup it }
}
}
maven {
url 'https://jitpack.io'
content {
// Use this repo only for olm library
includeGroupByRegex "org\\.matrix\\.gitlab\\.matrix-org"
// And also for FilePicker
includeGroupByRegex "com\\.github\\.jaiselrahman"
// And monarchy
includeGroupByRegex "com\\.github\\.Zhuinden"
// And ucrop
includeGroupByRegex "com\\.github\\.yalantis"
// JsonViewer
includeGroupByRegex 'com\\.github\\.BillCarsonFr'
// PhotoView
includeGroupByRegex 'com\\.github\\.chrisbanes'
// PFLockScreen-Android
includeGroupByRegex 'com\\.github\\.vector-im'
// DraggableView
includeGroupByRegex 'com\\.github\\.hyuwah'
// Chat effects
includeGroupByRegex 'com\\.github\\.jetradarmobile'
includeGroupByRegex 'nl\\.dionsegijn'
// Voice RecordView
includeGroupByRegex 'com\\.github\\.Armen101'
groups.jitpack.regex.each { includeGroupByRegex it }
groups.jitpack.group.each { includeGroup it }
}
}
maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
// Jitsi repo
maven {
url "https://github.com/vector-im/jitsi_libre_maven/raw/main/android-sdk-3.10.0"
// Note: to test Jitsi release you can use a local file like this:
// url "file:///Users/bmarty/workspaces/jitsi_libre_maven/android-sdk-3.10.0"
content {
groups.jitsi.regex.each { includeGroupByRegex it }
groups.jitsi.group.each { includeGroup it }
}
}
google {
content {
groups.google.regex.each { includeGroupByRegex it }
groups.google.group.each { includeGroup it }
}
}
mavenCentral {
content {
groups.mavenCentral.regex.each { includeGroupByRegex it }
groups.mavenCentral.group.each { includeGroup it }
}
}
//noinspection JcenterRepositoryObsolete
jcenter {
content {
groups.jcenter.regex.each { includeGroupByRegex it }
groups.jcenter.group.each { includeGroup it }
}
}
google()
mavenCentral()
jcenter()
}
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {

1
changelog.d/3473.bugfix Normal file
View File

@ -0,0 +1 @@
MSC2732: Olm fallback keys

View File

@ -1 +0,0 @@
Make Element Android Thread aware

1
changelog.d/4278.feature Normal file
View File

@ -0,0 +1 @@
Updates URL previews to match latest designs

1
changelog.d/4324.bugfix Normal file
View File

@ -0,0 +1 @@
Fixes message menu showing when copying message urls

View File

@ -1 +0,0 @@
Make the verification shields the same in Element Web and Element Android

View File

@ -1 +0,0 @@
Fix a display issue in the composer when the replied message is changed.

View File

@ -1 +0,0 @@
Upgrade Jitsi lib (and so webrtc) from Jitsi android-sdk-3.1.0 to android-sdk-3.10.0

View File

@ -1 +0,0 @@
Voice recording mic button refactor with small animation tweaks in preparation for voice drafts

View File

@ -1 +0,0 @@
Fix a crash when displaying the bootstrap bottom sheet

1
changelog.d/4546.bugfix Normal file
View File

@ -0,0 +1 @@
Fix lots of integration tests by introducing TestMatrix class and MatrixWorkerFactory.

1
changelog.d/4559.feature Normal file
View File

@ -0,0 +1 @@
Setup Analytics framework using PostHog. Analytics are disabled by default. Opt-in screen not automatically displayed yet.

1
changelog.d/4592.bugfix Normal file
View File

@ -0,0 +1 @@
Fix empty Dev Tools screen issue.

1
changelog.d/4600.misc Normal file
View File

@ -0,0 +1 @@
At the very first room search after opening the app sometimes no results are displayed

1
changelog.d/4602.misc Normal file
View File

@ -0,0 +1 @@
There is no need to call job.cancel() when we are using viewModelScope()

1
changelog.d/4604.misc Normal file
View File

@ -0,0 +1 @@
Cleanup the layout files

1
changelog.d/4617.misc Normal file
View File

@ -0,0 +1 @@
Improve issue automation workflows

1
changelog.d/4621.bugfix Normal file
View File

@ -0,0 +1 @@
Fix for outgoing voip call via sip bridge failing after 1 minute.

1
changelog.d/4626.misc Normal file
View File

@ -0,0 +1 @@
Introducing feature flagging to the login and notification settings flows

1
changelog.d/4636.bugfix Normal file
View File

@ -0,0 +1 @@
Update log warning for call selection during voip calls.

1
changelog.d/4638.feature Normal file
View File

@ -0,0 +1 @@
Add a help section in the settings.

1
changelog.d/4645.misc Normal file
View File

@ -0,0 +1 @@
Debounce some clicks

1
changelog.d/4647.misc Normal file
View File

@ -0,0 +1 @@
Upgrade OLM to v3.2.7 and get it from our maven repository.

1
changelog.d/4650.misc Normal file
View File

@ -0,0 +1 @@
Cleanup id ref. Use type views instead

1
changelog.d/4653.feature Normal file
View File

@ -0,0 +1 @@
Poll Feature - Render in timeline

1
changelog.d/4660.feature Normal file
View File

@ -0,0 +1 @@
Create a legal screen in the setting to group all the different policies.

1
changelog.d/4666.misc Normal file
View File

@ -0,0 +1 @@
Add automation to move message bubbles issues to message bubbles board.

1
changelog.d/4670.misc Normal file
View File

@ -0,0 +1 @@
Add explicit dependency location, regarding the several maven repository. Also update some libraries (flexbox and alerter), and do some cleanup.

1
changelog.d/4671.misc Normal file
View File

@ -0,0 +1 @@
Fix graphql warning in issue workflow automation

1
changelog.d/4693.bugfix Normal file
View File

@ -0,0 +1 @@
Fix possible crash when having identical subspaces in multiple root spaces

1
changelog.d/4698.bugfix Normal file
View File

@ -0,0 +1 @@
Fix a crash in the timeline with some Emojis. Also migrate to androidx.emoji2

View File

@ -7,11 +7,11 @@ ext.versions = [
'targetCompat' : JavaVersion.VERSION_11,
]
def gradle = "7.0.3"
def gradle = "7.0.4"
// Ref: https://kotlinlang.org/releases.html
def kotlin = "1.5.31"
def kotlinCoroutines = "1.5.2"
def dagger = "2.40.1"
def dagger = "2.40.5"
def retrofit = "2.9.0"
def arrow = "0.8.2"
def markwon = "4.6.2"
@ -19,7 +19,7 @@ def moshi = "1.12.0"
def lifecycle = "2.4.0"
def flowBinding = "1.2.0"
def epoxy = "4.6.2"
def mavericks = "2.4.0"
def mavericks = "2.5.0"
def glide = "4.12.0"
def bigImageViewer = "1.8.1"
def jjwt = "0.11.2"

201
dependencies_groups.gradle Normal file
View File

@ -0,0 +1,201 @@
ext.groups = [
jitpack : [
regex: [
],
group: [
'com.github.Armen101',
'com.github.BillCarsonFr',
'com.github.chrisbanes',
'com.github.hyuwah',
'com.github.jetradarmobile',
'com.github.tapadoo',
'com.github.vector-im',
'com.github.yalantis',
'com.github.Zhuinden',
]
],
olm : [
regex: [
],
group: [
'org.matrix.android',
]
],
jitsi : [
regex: [
],
group: [
'com.facebook.react',
'org.jitsi.react',
'org.webkit',
]
],
google : [
regex: [
'androidx\\..*',
'com\\.android\\.tools\\..*',
'com\\.google\\.android\\..*',
],
group: [
'com.google.firebase',
'com.android',
'com.android.tools',
]
],
mavenCentral: [
regex: [
],
group: [
'com.adevinta.android',
'com.airbnb.android',
'com.almworks.sqlite4java',
'com.arthenica',
'com.atlassian.commonmark',
'com.atlassian.pom',
'com.beust',
'com.davemorrissey.labs',
'com.dropbox.core',
'com.facebook.fresco',
'com.facebook.infer.annotation',
'com.facebook.soloader',
'com.facebook.stetho',
'com.fasterxml',
'com.fasterxml.jackson',
'com.fasterxml.jackson.core',
'com.gabrielittner.threetenbp',
'com.getkeepsafe.relinker',
'com.github.bumptech.glide',
'com.github.filippudak',
'com.github.filippudak.progresspieview',
'com.github.javaparser',
'com.github.piasy',
'com.github.shyiko.klob',
'com.google',
'com.google.auto.service',
'com.google.auto.value',
'com.google.code.findbugs',
'com.google.code.gson',
'com.google.dagger',
'com.google.devtools.ksp',
'com.google.errorprone',
'com.google.googlejavaformat',
'com.google.guava',
'com.google.j2objc',
'com.google.jimfs',
'com.google.protobuf',
'com.google.zxing',
'com.googlecode.htmlcompressor',
'com.googlecode.json-simple',
'com.googlecode.libphonenumber',
'com.ibm.icu',
'com.jakewharton.android.repackaged',
'com.jakewharton.timber',
'com.linkedin.dexmaker',
'com.nulab-inc',
'com.otaliastudios.opengl',
'com.parse.bolts',
'com.pinterest',
'com.pinterest.ktlint',
'com.posthog.android',
'com.squareup',
'com.squareup.duktape',
'com.squareup.moshi',
'com.squareup.okhttp3',
'com.squareup.okio',
'com.squareup.retrofit2',
'com.sun.activation',
'com.sun.istack',
'com.sun.xml.bind',
'com.sun.xml.bind.mvn',
'com.sun.xml.fastinfoset',
'com.thoughtworks.qdox',
'com.vanniktech',
'commons-cli',
'commons-codec',
'commons-io',
'commons-logging',
'info.picocli',
'io.arrow-kt',
'io.github.detekt.sarif4k',
'io.github.reactivecircus.flowbinding',
'io.jsonwebtoken',
'io.kindedj',
'io.mockk',
'io.noties.markwon',
'io.reactivex.rxjava2',
'io.realm',
'it.unimi.dsi',
'jakarta.activation',
'jakarta.xml.bind',
'javax.annotation',
'javax.inject',
'jline',
'jp.wasabeef',
'junit',
'me.leolin',
'me.saket',
'net.bytebuddy',
'net.java',
'net.java.dev.jna',
'net.lachlanmckee',
'net.ltgt.gradle.incap',
'net.sf.jopt-simple',
'net.sf.kxml',
'nl.dionsegijn',
'org.amshove.kluent',
'org.apache',
'org.apache.ant',
'org.apache.commons',
'org.apache.httpcomponents',
'org.apache.sanselan',
'org.bouncycastle',
'org.checkerframework',
'org.codehaus',
'org.codehaus.groovy',
'org.codehaus.mojo',
'org.eclipse.ee4j',
'org.ec4j.core',
'org.glassfish.jaxb',
'org.hamcrest',
'org.jetbrains',
'org.jetbrains.intellij.deps',
'org.jetbrains.kotlin',
'org.jetbrains.kotlinx',
'org.jsoup',
'org.junit',
'org.junit.jupiter',
'org.junit.platform',
'org.jvnet.staxex',
'org.mockito',
'org.mongodb',
'org.objenesis',
'org.opentest4j',
'org.ow2',
'org.ow2.asm',
'org.ow2.asm',
'org.reactivestreams',
'org.robolectric',
'org.slf4j',
'org.sonatype.oss',
'org.testng',
'org.threeten',
'xerces',
'xml-apis',
]
],
jcenter : [
regex: [
],
group: [
'com.amulyakhare',
'com.otaliastudios',
'com.yqritc',
// https://github.com/cmelchior/realmfieldnameshelper/issues/42
'dk.ilios',
'im.dlg',
'me.dm7.barcodescanner',
'me.gujun.android',
]
]
]

16
docs/analytics.md Normal file
View File

@ -0,0 +1,16 @@
# Analytics in Element
## Solution
Element is using PostHog to send analytics event.
We ask for the user to give consent before sending any analytics data.
## How to add a new Event
The analytics plan is shared between all Element clients. To add an Event, please open a PR to this project: https://github.com/matrix-org/matrix-analytics-events
Then, once the PR has been merged, you can run the tool `import_analytic_plan.sh` to import the plan to Element, and then you can use the new Event. Note that this tool is run by Github action once a week.
## Forks of Element
Analytics on forks are disabled by default. Please refer to AnalyticsConfig and there implementation to setup analytics on your project.

View File

@ -0,0 +1,2 @@
Hlavní změny v této verzi: Opravy chyb týkající se především oznámení.
Úplný seznam změn: https://github.com/vector-im/element-android/releases/tag/v1.3.7-RC2

View File

@ -0,0 +1,2 @@
Hlavní změny v této verzi: Opravy chyb!
Úplný seznam změn: https://github.com/vector-im/element-android/releases/tag/v1.3.8

View File

@ -0,0 +1,2 @@
Hauptänderungen: Fehler bei Benachrichtigungen gefixt
Ganze Änderungsliste: https://github.com/vector-im/element-android/releases/tag/v1.3.7-RC2

View File

@ -0,0 +1,2 @@
Änderungen: Verschiedene Fehler behoben
Änderungsliste: https://github.com/vector-im/element-android/releases/tag/v1.3.8

View File

@ -0,0 +1,2 @@
Main changes in this version: Add support for voice message draft. Many bugfixes!
Full changelog: https://github.com/vector-im/element-android/releases/tag/v1.3.9

View File

@ -0,0 +1,2 @@
Põhilised muutused selles versioonis: erinevad veaparandused, neist enamus on seotud teavitustega.
Kogu ingliskeelne muudatuste logi: https://github.com/vector-im/element-android/releases/tag/v1.3.7-RC2

View File

@ -0,0 +1,2 @@
Põhilised muutused selles versioonis: pinu veaparandusi!
Kogu ingliskeelne muudatuste logi: https://github.com/vector-im/element-android/releases/tag/v1.3.8

View File

@ -0,0 +1,2 @@
تغییرات اصلی در این نگارش: افزودن پشتیبانی حضور برای اتاق‌های پیام مستقیم (یادداشت: حضور روی matrix.org از کار افتاده است). افزودن دوبارهٔ پشتیبانی اندروید خودرو.
گزارش دگرگونی کامل: https://github.com/vector-im/element-android/releases/tag/v1.3.5

View File

@ -0,0 +1,2 @@
تغییرات اصلی در این نگارش: افزودن پشتیبانی حضور برای اتاق‌های پیام مستقیم (یادداشت: حضور روی matrix.org از کار افتاده است). افزودن دوبارهٔ پشتیبانی اندروید خودرو.
گزارش دگرگونی کامل: https://github.com/vector-im/element-android/releases/tag/v1.3.6

View File

@ -0,0 +1,2 @@
تغییرات اصلی در این نگارش: رفع اشکال‌هایی عمدتاً مربوط به آگاهی‌ها.
گزارش دگرگونی کامل: https://github.com/vector-im/element-android/releases/tag/v1.3.7-RC2

View File

@ -0,0 +1,2 @@
تغییرات عمده در این نگارش: رفع مشکل‌ها!
گزارش دگرکونی کامل: https://github.com/vector-im/element-android/releases/tag/v1.3.8

View File

@ -0,0 +1,2 @@
Principaux changements pour cette version : corrections de problèmes, principalement sur les notifications
Intégralité des changements : https://github.com/vector-im/element-android/releases/tag/v1.3.7-RC2

View File

@ -0,0 +1,2 @@
Principaux changements pour cette version : corrections de bugs !
Intégralité des changements : https://github.com/vector-im/element-android/releases/tag/v1.3.8

View File

@ -0,0 +1,2 @@
Fő változás ebben a verzióban: Értesítési hibajavítások
Teljes változásnapló: https://github.com/vector-im/element-android/releases/tag/v1.3.7-RC2

View File

@ -0,0 +1,2 @@
Főbb változtatások ebben a verzióban: Hibajavítások
Teljes változásnapló: https://github.com/vector-im/element-android/releases/tag/v1.3.8

View File

@ -0,0 +1,2 @@
Perubahan utama di versi ini: Perbaikan bug terutama untuk notifikasinya.
Changelog lengkap: https://github.com/vector-im/element-android/releases/tag/v1.3.7-RC2

View File

@ -0,0 +1,2 @@
Perubahan utama di versi ini: Beberapa perbaikan bug!
Changelog lengkap: https://github.com/vector-im/element-android/releases/tag/v1.3.8

View File

@ -26,7 +26,7 @@ Element menempatkan Anda dalam kendali dengan cara yang berbeda:
2. Host sendiri akun Anda dengan menjalankan server pada infrastruktur IT Anda sendiri
3. Daftar untuk akun di server khusus dengan berlangganan platform hosting Layanan Matrix Element
<b>Pesan terbuka dan kolaborasi</b>
<b>Perpesanan dan kolaborasi terbuka</b>
Anda dapat mengobrol dengan siapa saja di jaringan Matrix, jika mereka menggunakan Element, aplikasi Matrix lain atau bahkan menggunakan aplikasi perpesanan yang berbeda.
<b>Sangat aman</b>

View File

@ -0,0 +1,2 @@
Modifiche principali in questa versione: correzioni riguardo le notifiche.
Cronologia completa: https://github.com/vector-im/element-android/releases/tag/v1.3.7-RC2

View File

@ -0,0 +1,2 @@
Modifiche principali in questa versione: correzioni di errori!
Cronologia completa: https://github.com/vector-im/element-android/releases/tag/v1.3.8

View File

@ -0,0 +1,2 @@
Główne zmiany w tej wersji: Poprawki błędów dotyczące głównie powiadomień
Pełny changelog: https://github.com/vector-im/element-android/releases/tag/v1.3.7

View File

@ -0,0 +1,42 @@
Element jest bezpiecznym komunikatorem oraz narzędziem do komunikacji w zespole które jest idealna do pracy zdalnej. Nasza aplikacja korzysta z szyfrowania end-to-end aby rozmowy wideo, udostępnianie plików oraz rozmowy głosowe były bezpieczne.
<b>Funkcje Element'a:</b>
- Zaawansowane narzędzia komunikacji online
- W pełni szyfrowane wiadomości które umożliwiają bezpieczniejszą komunikacje dla firm, a nawet dla pracowników zdalnych.
- Zdecentralizowany czat bazowany na otwartym protokole Matrix
- Bezpieczne udostępnianie plików wraz z szyfrowaniem danych podczas zarządzania projektami
- Rozmowy z Voice over IP wraz z udostępnianiem ekranu
- Prosta konfiguracja z ulubionymi narzędziami do kolaboracji, narzędziami do zarządzania projektami usługami VoIP oraz innymi aplikacjami do komunikacji w grupie
Element jest całkowicie inny od innych komunikatorów i aplikacji do kolaboracji. Pracuje na protokole Matrix, otwarto źródłowej sieci stworzonej dla bezpiecznych wiadomości i zdecentralizowanej komunikacji. Pozwala ona na własny hosting serwera dla maksymalnej własności i kontroli nad danymi oraz wiadomościami.
<b>Prywatność i szyfrowane wiadomości</b>
Element broni cie przez niechcianymi wiadomościami, kopaniem informacji oraz cenzurą. Zabezpiecza wszystkie twoje dane, wideo które pozostaje wiadome tylko dla rozmawiających przez szyfrowanie end-to-end i weryfikacją krzyżową urządzeń.
Element daje kontrole nad twoją prywatnością i umożliwia bezpieczną komunikacje z kimkolwiek w sieci Matrix, lub z innymi firmami przez narzędzia do komunikacji integrując aplikacje takie jak Slack.
<b>Element może być hostowany samemu</b>
Pozwala to na kontrolę nad twoimi wrażliwymi danymi oraz rozmowami, Element może być hostowany samemu lub pozwala wybrać dowolnego hosta bazowanego na Matrix'ie - otwarto-źródłowym standardzie, dla zdecentralizowanej komunikacji. Element daje tobie prywatność, bezpieczeństwo oraz elastyczność w integracji.
<b>Posiadaj naprawdę swoje dane</b>
Ty decydujesz gdzie trzymasz swoje dane i wiadomości. Bez ryzyka wycieku lub dostępu firm trzecich.
Element daje ci kontrolę na wiele sposobów:
1. Utwórz darmowe konto na publicznym serwerze matrix.org hostowanym przez twórców Matrix'a lub wybierz którykolwiek z tysięcy serwerów hostowanych przez wolontariuszy
2. Hostuj samemu swoje konto przez własny serwer na twojej infrastrukturze
3. Zarejestruj się na specjalnym serwerze poprzez subskrybowanie hostingu na platformie Element Martix Services
<b>Otwarte wiadomości i kolaboracja</b>
Możesz rozmawiać z kimkolwiek w sieci Matrix, nie ważne czy korzystają z Element'a, czy z innej aplikacji wspierającej protokół Matrix, a nawet z osobami korzystającymi z innych komunikatorów.
<b>Niesamowicie bezpieczny</b>
Prawdziwe szyfrowanie end-to-end (tylko osoby w konwersacji mogą odszyfrować wiadomości), a także krzyżowa weryfikacja urządzeń.
<b>Pełna komunikacja i integracja</b>
Wiadomości, rozmowy głosowe i wideo, udostępnianie plików, ekranu, a nawet integracja z botami i widżetami. Twórz pokoje, społeczności, pozostań w kontakcie i załatwiaj to co chcesz.
<b>Kontynuuj gdzie skończyłeś</b>
Pozostań zawsze w kontakcie poprzez pełną synchornizację między urządzeniami oraz w sieci na https://app.element.io
<b>Otwarto źródłowy</b>
Element Android jest otwarto-źródłowym projektem, hostowanym na platformie GitHub. Prosimy o zgłaszanie wszelkich błędów i/lub wsparcie w tworzeniu naszego projektu na https://github.com/vector-im/element-android

View File

@ -0,0 +1 @@
Grupowy komunikator - szyfrowane wiadomosci, grupowe czaty oraz rozmowy wideo

View File

@ -0,0 +1 @@
Element - Bezpieczny Komunikator

View File

@ -0,0 +1,2 @@
Principais mudanças nesta versão: Consertos de bugs principalmente quanto às notificações.
Changelog completo: https://github.com/vector-im/element-android/releases/tag/v1.3.7-RC2

View File

@ -0,0 +1,2 @@
Principais mudanças nesta versão: Consertos de bugs!
Changelog completo: https://github.com/vector-im/element-android/releases/tag/v1.3.8

View File

@ -0,0 +1,2 @@
Hlavné zmeny v tejto verzii: Opravy chýb týkajúce sa najmä oznámení.
Úplný zoznam zmien: https://github.com/vector-im/element-android/releases/tag/v1.3.7-RC2

View File

@ -0,0 +1,2 @@
Hlavné zmeny v tejto verzii: Opravy chýb!
Úplný zoznam zmien: https://github.com/vector-im/element-android/releases/tag/v1.3.8

View File

@ -1 +1 @@
Zabezpečené konverzácie a VoIP. Ochráňte vaše údaje pred tretími stranami.
Skupinový messenger - šifrované správy, skupinové konverzácie a videohovory

View File

@ -0,0 +1,2 @@
Ndryshimet kryesore në këtë version: Ndreqje të metash të lidhura kryesisht me njoftimet.
Regjistër i plotë ndryshimesh: https://github.com/vector-im/element-android/releases/tag/v1.3.7-RC2

View File

@ -0,0 +1,2 @@
Ndryshimet kryesore në këtë version: Ndreqje të metash!
Regjistër i plotë ndryshimesh: https://github.com/vector-im/element-android/releases/tag/v1.3.8

View File

@ -0,0 +1,2 @@
Huvudsakliga ändringar i den här versionen: Buggfixar som huvudsakligen rör aviseringar.
Full ändringslogg: https://github.com/vector-im/element-android/releases/tag/v1.3.7-RC2

View File

@ -0,0 +1,2 @@
Huvudsakliga ändringar i den här versionen: Buggfixar!
Full ändringslogg: https://github.com/vector-im/element-android/releases/tag/v1.3.8

View File

@ -0,0 +1,2 @@
Основні зміни в цій версії: виправлення помилок в основному у повідомленнях.
Повний журнал змін: https://github.com/vector-im/element-android/releases/tag/v1.3.7-RC2

View File

@ -0,0 +1,2 @@
Основні зміни у цій версії: Виправлення помилок!
Повний перелік змін: https://github.com/vector-im/element-android/releases/tag/v1.3.8

View File

@ -1,7 +1,7 @@
Element — це і безпечний месенджер, і застосунок для співпраці команди, який ідеально підходить для групових бесід під час віддаленої роботи. Цей застосунок для спілкування застосовує наскрізне шифрування для забезпечення відеоконференцій, обміну файлами та голосових викликів.
Element — це і безпечний месенджер, і застосунок для співпраці команди, який ідеально підходить спілкування групами під час віддаленої роботи. Цей застосунок для спілкування використовує наскрізне шифрування для забезпечення відеоконференцій, обміну файлами та голосових викликів.
<b>Можливості Element включають:</b>
- Розширені засоби спілкування в Інтернеті
- Розширені засоби онлайн-спілкування
- Повністю зашифровані повідомлення для надання можливості безпечнішого корпоративного спілкування, навіть для віддалених працівників
- Децентралізований чат на основі відкритого коду Matrix
- Безпечний обмін файлами із зашифрованими даними для керування проєктами
@ -33,10 +33,10 @@ Element надає такі можливості на вибір:
Справжнє наскрізне шифрування (лише учасники бесіди можуть розшифровувати повідомлення) та взаємне підписування пристроїв.
<b>Повноцінні спілкування та інтеграція</b>
Обмін повідомленнями, голосові та відеовиклики, обмін файлами, спільний доступ до екрана та ціла купа інтеграцій, ботів та розширень. Створюйте кімнати, спільноти, залишайтеся на зв’язку та виконуйте завдання.
Обмін повідомленнями, голосові та відеовиклики, обмін файлами, спільний доступ до екрана та ціла купа інтеграцій, ботів та віджетів. Створюйте кімнати, спільноти, залишайтеся на зв’язку та виконуйте завдання.
<b>Продовжуйте, де зупинилися</b>
Залишайтеся на зв'язку, де б ви не знаходились, з повністю синхронізованою історією повідомлень на всіх своїх пристроях та в Інтернеті за адресою https://app.element.io
<b>Відкритий код</b>
Element для Android це проєкт з відкритим кодом, розміщений GitHub. Будь ласка, повідомте про помилки та/або сприяйте його розвитку на https://github.com/vector-im/element-android
Element для Android це проєкт з відкритим кодом, розміщений на GitHub. Повідомляйте про помилки та/або допомагайте його розвитку на https://github.com/vector-im/element-android

View File

@ -0,0 +1,2 @@
此版本的主要变化:主要关于通知的错误修复。
完整更新日志https://github.com/vector-im/element-android/releases/tag/v1.3.7-RC2

View File

@ -0,0 +1,2 @@
此版本主要变化Bug 修复!
完整更新日志https://github.com/vector-im/element-android/releases/tag/v1.3.8

View File

@ -0,0 +1,2 @@
此版本中的主要變動:主要關於通知的臭蟲修復。
完整的變更紀錄https://github.com/vector-im/element-android/releases/tag/v1.3.7-RC2

View File

@ -0,0 +1,2 @@
此版本中的主要變動:臭蟲修復!
完整的變更紀錄https://github.com/vector-im/element-android/releases/tag/v1.3.8

View File

@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionSha256Sum=00b273629df4ce46e68df232161d5a7c4e495b9a029ce6e0420f071e21316867
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-all.zip
distributionSha256Sum=b75392c5625a88bccd58a574552a5a323edca82dab5942d2d41097f809c6bcce
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.1-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@ -34,7 +34,7 @@
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/appBarLayout">
app:layout_constraintTop_toBottomOf="@id/appBarLayout">
<LinearLayout
android:layout_width="match_parent"
@ -334,7 +334,6 @@
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
style="@style/Widget.MaterialComponents.TextInputLayout.FilledBox"
android:layout_width="match_parent"

View File

@ -5,7 +5,6 @@
<item name="android:visibility">visible</item>
</style>
<style name="Theme.Debug.Light" parent="Theme.MaterialComponents.Light.NoActionBar">
<!-- Keep all default value -->
</style>

View File

@ -11,5 +11,3 @@
<changeImageTransform />
</transitionSet>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="width_percent">0.6</dimen>
</resources>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="width_percent">0.5</dimen>
</resources>

View File

@ -32,7 +32,6 @@
<dimen name="call_pip_width">88dp</dimen>
<dimen name="call_pip_radius">8dp</dimen>
<dimen name="item_form_min_height">76dp</dimen>
<!-- Max width for some buttons -->
@ -41,4 +40,6 @@
<!-- Navigation Drawer -->
<dimen name="navigation_drawer_max_width">320dp</dimen>
<!-- Preview Url -->
<dimen name="preview_url_view_corner_radius">8dp</dimen>
</resources>

View File

@ -20,7 +20,6 @@
<color name="palette_prune">#5C56F5</color>
<color name="palette_links">#0086E6</color>
<!-- For light themes -->
<color name="palette_gray_25">#F4F6FA</color>
<color name="palette_gray_50">#E3E8F0</color>

View File

@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="BadgeFloatingActionButton">

View File

@ -49,7 +49,6 @@
<item name="android:backgroundTint">@android:color/black</item>
</style>
<style name="Widget.Vector.Button.Outlined.SocialLogin.Facebook">
<item name="icon">@drawable/ic_social_facebook</item>
</style>
@ -68,7 +67,6 @@
<item name="android:backgroundTint">#3877EA</item>
</style>
<style name="Widget.Vector.Button.Outlined.SocialLogin.Twitter">
<item name="icon">@drawable/ic_social_twitter</item>
</style>
@ -85,7 +83,6 @@
<item name="android:backgroundTint">#5D9EC9</item>
</style>
<style name="Widget.Vector.Button.Outlined.SocialLogin.Apple">
<item name="icon">@drawable/ic_social_apple</item>
</style>
@ -118,5 +115,4 @@
<item name="android:backgroundTint">@android:color/black</item>
</style>
</resources>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="width_percent">1</dimen>
</resources>

View File

@ -9,7 +9,7 @@ buildscript {
mavenCentral()
}
dependencies {
classpath "io.realm:realm-gradle-plugin:10.8.1"
classpath "io.realm:realm-gradle-plugin:10.9.0"
}
}
@ -31,7 +31,7 @@ android {
// that the app's state is completely cleared between tests.
testInstrumentationRunnerArguments clearPackageData: 'true'
buildConfigField "String", "SDK_VERSION", "\"1.3.9\""
buildConfigField "String", "SDK_VERSION", "\"1.3.10\""
buildConfigField "String", "GIT_SDK_REVISION", "\"${gitRevision()}\""
resValue "string", "git_sdk_revision", "\"${gitRevision()}\""
@ -115,7 +115,7 @@ dependencies {
implementation libs.squareup.retrofit
implementation libs.squareup.retrofitMoshi
implementation(platform("com.squareup.okhttp3:okhttp-bom:4.9.2"))
implementation(platform("com.squareup.okhttp3:okhttp-bom:4.9.3"))
implementation 'com.squareup.okhttp3:okhttp'
implementation 'com.squareup.okhttp3:logging-interceptor'
implementation 'com.squareup.okhttp3:okhttp-urlconnection'
@ -140,8 +140,8 @@ dependencies {
implementation libs.arrow.core
implementation libs.arrow.instances
// olm lib is now hosted by jitpack: https://jitpack.io/#org.matrix.gitlab.matrix-org/olm
implementation 'org.matrix.gitlab.matrix-org:olm:3.2.4'
// olm lib is now hosted by maven at https://gitlab.matrix.org/api/v4/projects/27/packages/maven
implementation 'org.matrix.android:olm:3.2.7'
// DI
implementation libs.dagger.dagger
@ -158,10 +158,10 @@ dependencies {
implementation libs.apache.commonsImaging
// Phone number https://github.com/google/libphonenumber
implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.37'
implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.39'
testImplementation libs.tests.junit
testImplementation 'org.robolectric:robolectric:4.7.1'
testImplementation 'org.robolectric:robolectric:4.7.3'
//testImplementation 'org.robolectric:shadows-support-v4:3.0'
// Note: version sticks to 1.9.2 due to https://github.com/mockk/mockk/issues/281
testImplementation libs.mockk.mockk

View File

@ -20,9 +20,10 @@ import android.content.Context
import android.net.Uri
import androidx.lifecycle.Observer
import androidx.test.internal.runner.junit4.statement.UiThreadStatement
import androidx.test.internal.runner.junit4.statement.UiThreadStatement.runOnUiThread
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
@ -30,7 +31,6 @@ import kotlinx.coroutines.withTimeout
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertTrue
import org.matrix.android.sdk.api.Matrix
import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.MatrixConfiguration
import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig
@ -45,7 +45,7 @@ import org.matrix.android.sdk.api.session.room.timeline.Timeline
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings
import org.matrix.android.sdk.api.session.sync.SyncState
import java.util.ArrayList
import timber.log.Timber
import java.util.UUID
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
@ -56,13 +56,14 @@ import java.util.concurrent.TimeUnit
*/
class CommonTestHelper(context: Context) {
val matrix: Matrix
internal val matrix: TestMatrix
val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
fun getTestInterceptor(session: Session): MockOkHttpInterceptor? = TestNetworkModule.interceptorForSession(session.sessionId) as? MockOkHttpInterceptor
fun getTestInterceptor(session: Session): MockOkHttpInterceptor? = TestModule.interceptorForSession(session.sessionId) as? MockOkHttpInterceptor
init {
UiThreadStatement.runOnUiThread {
Matrix.initialize(
TestMatrix.initialize(
context,
MatrixConfiguration(
applicationFlavor = "TestFlavor",
@ -70,7 +71,7 @@ class CommonTestHelper(context: Context) {
)
)
}
matrix = Matrix.getInstance(context)
matrix = TestMatrix.getInstance(context)
}
fun createAccount(userNamePrefix: String, testParams: SessionTestParams): Session {
@ -95,33 +96,47 @@ class CommonTestHelper(context: Context) {
*
* @param session the session to sync
*/
@Suppress("EXPERIMENTAL_API_USAGE")
fun syncSession(session: Session, timeout: Long = TestConstants.timeOutMillis) {
fun syncSession(session: Session, timeout: Long = TestConstants.timeOutMillis * 10) {
val lock = CountDownLatch(1)
val job = GlobalScope.launch(Dispatchers.Main) {
session.open()
}
runBlocking { job.join() }
session.startSync(true)
val syncLiveData = runBlocking(Dispatchers.Main) {
session.getSyncStateLive()
}
val syncObserver = object : Observer<SyncState> {
override fun onChanged(t: SyncState?) {
if (session.hasAlreadySynced()) {
lock.countDown()
syncLiveData.removeObserver(this)
coroutineScope.launch {
session.startSync(true)
val syncLiveData = session.getSyncStateLive()
val syncObserver = object : Observer<SyncState> {
override fun onChanged(t: SyncState?) {
if (session.hasAlreadySynced()) {
lock.countDown()
syncLiveData.removeObserver(this)
}
}
}
syncLiveData.observeForever(syncObserver)
}
GlobalScope.launch(Dispatchers.Main) { syncLiveData.observeForever(syncObserver) }
await(lock, timeout)
}
/**
* This methods clear the cache and waits for initialSync
*
* @param session the session to sync
*/
fun clearCacheAndSync(session: Session, timeout: Long = TestConstants.timeOutMillis) {
waitWithLatch(timeout) { latch ->
session.clearCache()
val syncLiveData = session.getSyncStateLive()
val syncObserver = object : Observer<SyncState> {
override fun onChanged(t: SyncState?) {
if (session.hasAlreadySynced()) {
Timber.v("Clear cache and synced")
syncLiveData.removeObserver(this)
latch.countDown()
}
}
}
syncLiveData.observeForever(syncObserver)
session.startSync(true)
}
}
/**
* Sends text messages in a room
*
@ -130,46 +145,57 @@ class CommonTestHelper(context: Context) {
* @param nbOfMessages the number of time the message will be sent
*/
fun sendTextMessage(room: Room, message: String, nbOfMessages: Int, timeout: Long = TestConstants.timeOutMillis): List<TimelineEvent> {
val timeline = room.createTimeline(null, TimelineSettings(10))
val sentEvents = ArrayList<TimelineEvent>(nbOfMessages)
val latch = CountDownLatch(1)
val timelineListener = object : Timeline.Listener {
override fun onTimelineFailure(throwable: Throwable) {
}
val timeline = room.createTimeline(null, TimelineSettings(10))
timeline.start()
waitWithLatch(timeout + 1_000L * nbOfMessages) { latch ->
val timelineListener = object : Timeline.Listener {
override fun onTimelineFailure(throwable: Throwable) {
}
override fun onNewTimelineEvents(eventIds: List<String>) {
// noop
}
override fun onNewTimelineEvents(eventIds: List<String>) {
// noop
}
override fun onTimelineUpdated(snapshot: List<TimelineEvent>) {
val newMessages = snapshot
.filter { it.root.sendState == SendState.SYNCED }
.filter { it.root.getClearType() == EventType.MESSAGE }
.filter { it.root.getClearContent().toModel<MessageContent>()?.body?.startsWith(message) == true }
override fun onTimelineUpdated(snapshot: List<TimelineEvent>) {
val newMessages = snapshot
.filter { it.root.sendState == SendState.SYNCED }
.filter { it.root.getClearType() == EventType.MESSAGE }
.filter { it.root.getClearContent().toModel<MessageContent>()?.body?.startsWith(message) == true }
if (newMessages.size == nbOfMessages) {
sentEvents.addAll(newMessages)
// Remove listener now, if not at the next update sendEvents could change
timeline.removeListener(this)
latch.countDown()
Timber.v("New synced message size: ${newMessages.size}")
if (newMessages.size == nbOfMessages) {
sentEvents.addAll(newMessages)
// Remove listener now, if not at the next update sendEvents could change
timeline.removeListener(this)
latch.countDown()
}
}
}
timeline.addListener(timelineListener)
sendTextMessagesBatched(room, message, nbOfMessages)
}
timeline.start()
timeline.addListener(timelineListener)
for (i in 0 until nbOfMessages) {
room.sendTextMessage(message + " #" + (i + 1))
}
// Wait 3 second more per message
await(latch, timeout = timeout + 3_000L * nbOfMessages)
timeline.dispose()
// Check that all events has been created
assertEquals("Message number do not match $sentEvents", nbOfMessages.toLong(), sentEvents.size.toLong())
return sentEvents
}
/**
* Will send nb of messages provided by count parameter but waits a bit every 10 messages to avoid gap in sync
*/
private fun sendTextMessagesBatched(room: Room, message: String, count: Int) {
(1 until count + 1)
.map { "$message #$it" }
.chunked(10)
.forEach { batchedMessages ->
batchedMessages.forEach { formattedMessage ->
room.sendTextMessage(formattedMessage)
}
Thread.sleep(1_000L)
}
}
// PRIVATE METHODS *****************************************************************************
/**
@ -239,10 +265,10 @@ class CommonTestHelper(context: Context) {
assertTrue(registrationResult is RegistrationResult.Success)
val session = (registrationResult as RegistrationResult.Success).session
session.open()
if (sessionTestParams.withInitialSync) {
syncSession(session, 60_000)
}
return session
}
@ -267,7 +293,7 @@ class CommonTestHelper(context: Context) {
.getLoginWizard()
.login(userName, password, "myDevice")
}
session.open()
if (sessionTestParams.withInitialSync) {
syncSession(session)
}
@ -332,22 +358,21 @@ class CommonTestHelper(context: Context) {
assertTrue(latch.await(timeout ?: TestConstants.timeOutMillis, TimeUnit.MILLISECONDS))
}
@Suppress("EXPERIMENTAL_API_USAGE")
fun retryPeriodicallyWithLatch(latch: CountDownLatch, condition: (() -> Boolean)) {
GlobalScope.launch {
while (true) {
delay(1000)
if (condition()) {
latch.countDown()
return@launch
}
suspend fun retryPeriodicallyWithLatch(latch: CountDownLatch, condition: (() -> Boolean)) {
while (true) {
delay(1000)
if (condition()) {
latch.countDown()
return
}
}
}
fun waitWithLatch(timeout: Long? = TestConstants.timeOutMillis, block: (CountDownLatch) -> Unit) {
fun waitWithLatch(timeout: Long? = TestConstants.timeOutMillis, dispatcher: CoroutineDispatcher = Dispatchers.Main, block: suspend (CountDownLatch) -> Unit) {
val latch = CountDownLatch(1)
block(latch)
coroutineScope.launch(dispatcher) {
block(latch)
}
await(latch, timeout)
}

View File

@ -19,10 +19,6 @@ package org.matrix.android.sdk.common
import android.os.SystemClock
import android.util.Log
import androidx.lifecycle.Observer
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertNull
@ -31,6 +27,7 @@ import org.matrix.android.sdk.api.auth.UIABaseAuth
import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor
import org.matrix.android.sdk.api.auth.UserPasswordAuth
import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse
import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.crypto.verification.IncomingSasVerificationTransaction
import org.matrix.android.sdk.api.session.crypto.verification.OutgoingSasVerificationTransaction
@ -44,16 +41,16 @@ import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.model.RoomSummary
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
import org.matrix.android.sdk.api.util.Optional
import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM
import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM_BACKUP
import org.matrix.android.sdk.internal.crypto.keysbackup.model.MegolmBackupAuthData
import org.matrix.android.sdk.internal.crypto.keysbackup.model.MegolmBackupCreationInfo
import java.util.UUID
import java.util.concurrent.CountDownLatch
import kotlin.coroutines.Continuation
import kotlin.coroutines.resume
class CryptoTestHelper(private val mTestHelper: CommonTestHelper) {
class CryptoTestHelper(private val testHelper: CommonTestHelper) {
private val messagesFromAlice: List<String> = listOf("0 - Hello I'm Alice!", "4 - Go!")
private val messagesFromBob: List<String> = listOf("1 - Hello I'm Bob!", "2 - Isn't life grand?", "3 - Let's go to the opera.")
@ -64,27 +61,33 @@ class CryptoTestHelper(private val mTestHelper: CommonTestHelper) {
* @return alice session
*/
fun doE2ETestWithAliceInARoom(encryptedRoom: Boolean = true): CryptoTestData {
val aliceSession = mTestHelper.createAccount(TestConstants.USER_ALICE, defaultSessionParams)
val aliceSession = testHelper.createAccount(TestConstants.USER_ALICE, defaultSessionParams)
val roomId = mTestHelper.runBlockingTest {
val roomId = testHelper.runBlockingTest {
aliceSession.createRoom(CreateRoomParams().apply { name = "MyRoom" })
}
if (encryptedRoom) {
val room = aliceSession.getRoom(roomId)!!
mTestHelper.runBlockingTest {
testHelper.waitWithLatch { latch ->
val room = aliceSession.getRoom(roomId)!!
room.enableEncryption()
val roomSummaryLive = room.getRoomSummaryLive()
val roomSummaryObserver = object : Observer<Optional<RoomSummary>> {
override fun onChanged(roomSummary: Optional<RoomSummary>) {
if (roomSummary.getOrNull()?.isEncrypted.orFalse()) {
roomSummaryLive.removeObserver(this)
latch.countDown()
}
}
}
roomSummaryLive.observeForever(roomSummaryObserver)
}
}
return CryptoTestData(roomId, listOf(aliceSession))
}
/**
* @return alice and bob sessions
*/
@Suppress("EXPERIMENTAL_API_USAGE")
fun doE2ETestWithAliceAndBobInARoom(encryptedRoom: Boolean = true): CryptoTestData {
val cryptoTestData = doE2ETestWithAliceInARoom(encryptedRoom)
val aliceSession = cryptoTestData.firstSession
@ -92,54 +95,37 @@ class CryptoTestHelper(private val mTestHelper: CommonTestHelper) {
val aliceRoom = aliceSession.getRoom(aliceRoomId)!!
val bobSession = mTestHelper.createAccount(TestConstants.USER_BOB, defaultSessionParams)
val bobSession = testHelper.createAccount(TestConstants.USER_BOB, defaultSessionParams)
val lock1 = CountDownLatch(1)
val bobRoomSummariesLive = runBlocking(Dispatchers.Main) {
bobSession.getRoomSummariesLive(roomSummaryQueryParams { })
}
val newRoomObserver = object : Observer<List<RoomSummary>> {
override fun onChanged(t: List<RoomSummary>?) {
if (t?.isNotEmpty() == true) {
lock1.countDown()
bobRoomSummariesLive.removeObserver(this)
testHelper.waitWithLatch { latch ->
val bobRoomSummariesLive = bobSession.getRoomSummariesLive(roomSummaryQueryParams { })
val newRoomObserver = object : Observer<List<RoomSummary>> {
override fun onChanged(t: List<RoomSummary>?) {
if (t?.isNotEmpty() == true) {
bobRoomSummariesLive.removeObserver(this)
latch.countDown()
}
}
}
}
GlobalScope.launch(Dispatchers.Main) {
bobRoomSummariesLive.observeForever(newRoomObserver)
}
mTestHelper.runBlockingTest {
aliceRoom.invite(bobSession.myUserId)
}
mTestHelper.await(lock1)
val lock = CountDownLatch(1)
val roomJoinedObserver = object : Observer<List<RoomSummary>> {
override fun onChanged(t: List<RoomSummary>?) {
if (bobSession.getRoom(aliceRoomId)
?.getRoomMember(aliceSession.myUserId)
?.membership == Membership.JOIN) {
lock.countDown()
bobRoomSummariesLive.removeObserver(this)
testHelper.waitWithLatch { latch ->
val bobRoomSummariesLive = bobSession.getRoomSummariesLive(roomSummaryQueryParams { })
val roomJoinedObserver = object : Observer<List<RoomSummary>> {
override fun onChanged(t: List<RoomSummary>?) {
if (bobSession.getRoom(aliceRoomId)
?.getRoomMember(bobSession.myUserId)
?.membership == Membership.JOIN) {
bobRoomSummariesLive.removeObserver(this)
latch.countDown()
}
}
}
}
GlobalScope.launch(Dispatchers.Main) {
bobRoomSummariesLive.observeForever(roomJoinedObserver)
bobSession.joinRoom(aliceRoomId)
}
mTestHelper.runBlockingTest { bobSession.joinRoom(aliceRoomId) }
mTestHelper.await(lock)
// Ensure bob can send messages to the room
// val roomFromBobPOV = bobSession.getRoom(aliceRoomId)!!
// assertNotNull(roomFromBobPOV.powerLevels)
@ -171,13 +157,13 @@ class CryptoTestHelper(private val mTestHelper: CommonTestHelper) {
* @Return Sam session
*/
fun createSamAccountAndInviteToTheRoom(room: Room): Session {
val samSession = mTestHelper.createAccount(TestConstants.USER_SAM, defaultSessionParams)
val samSession = testHelper.createAccount(TestConstants.USER_SAM, defaultSessionParams)
mTestHelper.runBlockingTest {
testHelper.runBlockingTest {
room.invite(samSession.myUserId, null)
}
mTestHelper.runBlockingTest {
testHelper.runBlockingTest {
samSession.joinRoom(room.roomId, null, emptyList())
}
@ -194,23 +180,20 @@ class CryptoTestHelper(private val mTestHelper: CommonTestHelper) {
val bobSession = cryptoTestData.secondSession!!
bobSession.cryptoService().setWarnOnUnknownDevices(false)
aliceSession.cryptoService().setWarnOnUnknownDevices(false)
val roomFromBobPOV = bobSession.getRoom(aliceRoomId)!!
val roomFromAlicePOV = aliceSession.getRoom(aliceRoomId)!!
// Alice sends a message
mTestHelper.sendTextMessage(roomFromAlicePOV, messagesFromAlice[0], 1)
// roomFromAlicePOV.sendTextMessage(messagesFromAlice[0])
testHelper.sendTextMessage(roomFromAlicePOV, messagesFromAlice[0], 1)
// Bob send 3 messages
mTestHelper.sendTextMessage(roomFromBobPOV, messagesFromBob[0], 1)
mTestHelper.sendTextMessage(roomFromBobPOV, messagesFromBob[1], 1)
mTestHelper.sendTextMessage(roomFromBobPOV, messagesFromBob[2], 1)
testHelper.sendTextMessage(roomFromBobPOV, messagesFromBob[0], 1)
testHelper.sendTextMessage(roomFromBobPOV, messagesFromBob[1], 1)
testHelper.sendTextMessage(roomFromBobPOV, messagesFromBob[2], 1)
// Alice sends a message
mTestHelper.sendTextMessage(roomFromAlicePOV, messagesFromAlice[1], 1)
testHelper.sendTextMessage(roomFromAlicePOV, messagesFromAlice[1], 1)
return cryptoTestData
}
@ -256,60 +239,44 @@ class CryptoTestHelper(private val mTestHelper: CommonTestHelper) {
)
}
@Suppress("EXPERIMENTAL_API_USAGE")
fun createDM(alice: Session, bob: Session): String {
val roomId = mTestHelper.runBlockingTest {
alice.createDirectRoom(bob.myUserId)
}
mTestHelper.waitWithLatch { latch ->
val bobRoomSummariesLive = runBlocking(Dispatchers.Main) {
bob.getRoomSummariesLive(roomSummaryQueryParams { })
}
var roomId: String = ""
testHelper.waitWithLatch { latch ->
roomId = alice.createDirectRoom(bob.myUserId)
val bobRoomSummariesLive = bob.getRoomSummariesLive(roomSummaryQueryParams { })
val newRoomObserver = object : Observer<List<RoomSummary>> {
override fun onChanged(t: List<RoomSummary>?) {
val indexOfFirst = t?.indexOfFirst { it.roomId == roomId } ?: -1
if (indexOfFirst != -1) {
latch.countDown()
bobRoomSummariesLive.removeObserver(this)
latch.countDown()
}
}
}
GlobalScope.launch(Dispatchers.Main) {
bobRoomSummariesLive.observeForever(newRoomObserver)
}
bobRoomSummariesLive.observeForever(newRoomObserver)
}
mTestHelper.waitWithLatch { latch ->
val bobRoomSummariesLive = runBlocking(Dispatchers.Main) {
bob.getRoomSummariesLive(roomSummaryQueryParams { })
}
testHelper.waitWithLatch { latch ->
val bobRoomSummariesLive = bob.getRoomSummariesLive(roomSummaryQueryParams { })
val newRoomObserver = object : Observer<List<RoomSummary>> {
override fun onChanged(t: List<RoomSummary>?) {
if (bob.getRoom(roomId)
?.getRoomMember(bob.myUserId)
?.membership == Membership.JOIN) {
latch.countDown()
bobRoomSummariesLive.removeObserver(this)
latch.countDown()
}
}
}
GlobalScope.launch(Dispatchers.Main) {
bobRoomSummariesLive.observeForever(newRoomObserver)
}
mTestHelper.runBlockingTest { bob.joinRoom(roomId) }
bobRoomSummariesLive.observeForever(newRoomObserver)
bob.joinRoom(roomId)
}
return roomId
}
fun initializeCrossSigning(session: Session) {
mTestHelper.doSync<Unit> {
testHelper.doSync<Unit> {
session.cryptoService().crossSigningService()
.initializeCrossSigning(
object : UserInteractiveAuthInterceptor {
@ -346,8 +313,8 @@ class CryptoTestHelper(private val mTestHelper: CommonTestHelper) {
var bobPovTx: IncomingSasVerificationTransaction? = null
// wait for alice to get the ready
mTestHelper.waitWithLatch {
mTestHelper.retryPeriodicallyWithLatch(it) {
testHelper.waitWithLatch {
testHelper.retryPeriodicallyWithLatch(it) {
bobPovTx = bobVerificationService.getExistingTransaction(alice.myUserId, requestID) as? IncomingSasVerificationTransaction
Log.v("TEST", "== bobPovTx is ${alicePovTx?.uxState}")
if (bobPovTx?.state == VerificationTxState.OnStarted) {
@ -359,16 +326,16 @@ class CryptoTestHelper(private val mTestHelper: CommonTestHelper) {
}
}
mTestHelper.waitWithLatch {
mTestHelper.retryPeriodicallyWithLatch(it) {
testHelper.waitWithLatch {
testHelper.retryPeriodicallyWithLatch(it) {
alicePovTx = aliceVerificationService.getExistingTransaction(bob.myUserId, requestID) as? OutgoingSasVerificationTransaction
Log.v("TEST", "== alicePovTx is ${alicePovTx?.uxState}")
alicePovTx?.state == VerificationTxState.ShortCodeReady
}
}
// wait for alice to get the ready
mTestHelper.waitWithLatch {
mTestHelper.retryPeriodicallyWithLatch(it) {
testHelper.waitWithLatch {
testHelper.retryPeriodicallyWithLatch(it) {
bobPovTx = bobVerificationService.getExistingTransaction(alice.myUserId, requestID) as? IncomingSasVerificationTransaction
Log.v("TEST", "== bobPovTx is ${alicePovTx?.uxState}")
if (bobPovTx?.state == VerificationTxState.OnStarted) {
@ -383,38 +350,38 @@ class CryptoTestHelper(private val mTestHelper: CommonTestHelper) {
bobPovTx!!.userHasVerifiedShortCode()
alicePovTx!!.userHasVerifiedShortCode()
mTestHelper.waitWithLatch {
mTestHelper.retryPeriodicallyWithLatch(it) {
testHelper.waitWithLatch {
testHelper.retryPeriodicallyWithLatch(it) {
alice.cryptoService().crossSigningService().isUserTrusted(bob.myUserId)
}
}
mTestHelper.waitWithLatch {
mTestHelper.retryPeriodicallyWithLatch(it) {
testHelper.waitWithLatch {
testHelper.retryPeriodicallyWithLatch(it) {
alice.cryptoService().crossSigningService().isUserTrusted(bob.myUserId)
}
}
}
fun doE2ETestWithManyMembers(numberOfMembers: Int): CryptoTestData {
val aliceSession = mTestHelper.createAccount(TestConstants.USER_ALICE, defaultSessionParams)
val aliceSession = testHelper.createAccount(TestConstants.USER_ALICE, defaultSessionParams)
aliceSession.cryptoService().setWarnOnUnknownDevices(false)
val roomId = mTestHelper.runBlockingTest {
val roomId = testHelper.runBlockingTest {
aliceSession.createRoom(CreateRoomParams().apply { name = "MyRoom" })
}
val room = aliceSession.getRoom(roomId)!!
mTestHelper.runBlockingTest {
testHelper.runBlockingTest {
room.enableEncryption()
}
val sessions = mutableListOf(aliceSession)
for (index in 1 until numberOfMembers) {
val session = mTestHelper.createAccount("User_$index", defaultSessionParams)
mTestHelper.runBlockingTest(timeout = 600_000) { room.invite(session.myUserId, null) }
val session = testHelper.createAccount("User_$index", defaultSessionParams)
testHelper.runBlockingTest(timeout = 600_000) { room.invite(session.myUserId, null) }
println("TEST -> " + session.myUserId + " invited")
mTestHelper.runBlockingTest { session.joinRoom(room.roomId, null, emptyList()) }
testHelper.runBlockingTest { session.joinRoom(room.roomId, null, emptyList()) }
println("TEST -> " + session.myUserId + " joined")
sessions.add(session)
}

View File

@ -0,0 +1,31 @@
/*
* 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.common
import org.matrix.android.sdk.internal.util.BackgroundDetectionObserver
/**
* Force foreground for testing
*/
internal class TestBackgroundDetectionObserver : BackgroundDetectionObserver {
override val isInBackground: Boolean = false
override fun register(listener: BackgroundDetectionObserver.Listener) = Unit
override fun unregister(listener: BackgroundDetectionObserver.Listener) = Unit
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2020 The Matrix.org Foundation C.I.C.
* Copyright (c) 2021 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.matrix.android.sdk.api
package org.matrix.android.sdk.common
import android.content.Context
import android.os.Handler
@ -24,27 +24,27 @@ import androidx.work.Configuration
import androidx.work.WorkManager
import com.zhuinden.monarchy.Monarchy
import org.matrix.android.sdk.BuildConfig
import org.matrix.android.sdk.api.MatrixConfiguration
import org.matrix.android.sdk.api.auth.AuthenticationService
import org.matrix.android.sdk.api.auth.HomeServerHistoryService
import org.matrix.android.sdk.api.legacy.LegacySessionImporter
import org.matrix.android.sdk.api.network.ApiInterceptorListener
import org.matrix.android.sdk.api.network.ApiPath
import org.matrix.android.sdk.api.raw.RawService
import org.matrix.android.sdk.common.DaggerTestMatrixComponent
import org.matrix.android.sdk.internal.SessionManager
import org.matrix.android.sdk.internal.network.ApiInterceptor
import org.matrix.android.sdk.internal.network.UserAgentHolder
import org.matrix.android.sdk.internal.util.BackgroundDetectionObserver
import org.matrix.android.sdk.internal.worker.MatrixWorkerFactory
import org.matrix.olm.OlmManager
import java.util.concurrent.Executors
import java.util.concurrent.atomic.AtomicBoolean
import javax.inject.Inject
/**
* This is the main entry point to the matrix sdk.
* To get the singleton instance, use getInstance static method.
* This mimics the Matrix class but using TestMatrixComponent internally instead of regular MatrixComponent.
*/
class Matrix private constructor(context: Context, matrixConfiguration: MatrixConfiguration) {
internal class TestMatrix constructor(context: Context, matrixConfiguration: MatrixConfiguration) {
@Inject internal lateinit var legacySessionImporter: LegacySessionImporter
@Inject internal lateinit var authenticationService: AuthenticationService
@ -55,15 +55,18 @@ class Matrix private constructor(context: Context, matrixConfiguration: MatrixCo
@Inject internal lateinit var sessionManager: SessionManager
@Inject internal lateinit var homeServerHistoryService: HomeServerHistoryService
@Inject internal lateinit var apiInterceptor: ApiInterceptor
@Inject internal lateinit var matrixWorkerFactory: MatrixWorkerFactory
private val uiHandler = Handler(Looper.getMainLooper())
init {
Monarchy.init(context)
DaggerTestMatrixComponent.factory().create(context, matrixConfiguration).inject(this)
if (context.applicationContext !is Configuration.Provider) {
WorkManager.initialize(context, Configuration.Builder().setExecutor(Executors.newCachedThreadPool()).build())
}
val configuration = Configuration.Builder()
.setExecutor(Executors.newCachedThreadPool())
.setWorkerFactory(matrixWorkerFactory)
.build()
WorkManager.initialize(context, configuration)
uiHandler.post {
ProcessLifecycleOwner.get().lifecycle.addObserver(backgroundDetectionObserver)
}
@ -93,21 +96,21 @@ class Matrix private constructor(context: Context, matrixConfiguration: MatrixCo
companion object {
private lateinit var instance: Matrix
private lateinit var instance: TestMatrix
private val isInit = AtomicBoolean(false)
fun initialize(context: Context, matrixConfiguration: MatrixConfiguration) {
if (isInit.compareAndSet(false, true)) {
instance = Matrix(context.applicationContext, matrixConfiguration)
instance = TestMatrix(context.applicationContext, matrixConfiguration)
}
}
fun getInstance(context: Context): Matrix {
fun getInstance(context: Context): TestMatrix {
if (isInit.compareAndSet(false, true)) {
val appContext = context.applicationContext
if (appContext is MatrixConfiguration.Provider) {
val matrixConfiguration = (appContext as MatrixConfiguration.Provider).providesMatrixConfiguration()
instance = Matrix(appContext, matrixConfiguration)
instance = TestMatrix(appContext, matrixConfiguration)
} else {
throw IllegalStateException("Matrix is not initialized properly." +
" You should call Matrix.initialize or let your application implements MatrixConfiguration.Provider.")

View File

@ -34,12 +34,13 @@ import org.matrix.android.sdk.internal.util.system.SystemModule
NetworkModule::class,
AuthModule::class,
RawModule::class,
SystemModule::class,
TestNetworkModule::class
SystemModule::class
])
@MatrixScope
internal interface TestMatrixComponent : MatrixComponent {
fun inject(matrix: TestMatrix)
@Component.Factory
interface Factory {
fun create(@BindsInstance context: Context,

View File

@ -18,10 +18,39 @@ package org.matrix.android.sdk.common
import dagger.Binds
import dagger.Module
import dagger.Provides
import org.matrix.android.sdk.internal.di.MatrixComponent
import org.matrix.android.sdk.internal.di.MatrixScope
import org.matrix.android.sdk.internal.session.MockHttpInterceptor
import org.matrix.android.sdk.internal.session.TestInterceptor
import org.matrix.android.sdk.internal.util.BackgroundDetectionObserver
@Module
internal abstract class TestModule {
@Binds
abstract fun providesMatrixComponent(testMatrixComponent: TestMatrixComponent): MatrixComponent
@Module
companion object {
val interceptors = ArrayList<TestInterceptor>()
fun interceptorForSession(sessionId: String): TestInterceptor? = interceptors.firstOrNull { it.sessionId == sessionId }
@Provides
@JvmStatic
@MockHttpInterceptor
fun providesTestInterceptor(): TestInterceptor? {
return MockOkHttpInterceptor().also {
interceptors.add(it)
}
}
@Provides
@JvmStatic
@MatrixScope
fun providesBackgroundDetectionObserver(): BackgroundDetectionObserver {
return TestBackgroundDetectionObserver()
}
}
}

View File

@ -36,12 +36,12 @@ import org.matrix.android.sdk.internal.crypto.model.event.RoomKeyContent
@FixMethodOrder(MethodSorters.JVM)
class PreShareKeysTest : InstrumentedTest {
private val mTestHelper = CommonTestHelper(context())
private val mCryptoTestHelper = CryptoTestHelper(mTestHelper)
private val testHelper = CommonTestHelper(context())
private val cryptoTestHelper = CryptoTestHelper(testHelper)
@Test
fun ensure_outbound_session_happy_path() {
val testData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true)
val testData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true)
val e2eRoomID = testData.roomId
val aliceSession = testData.firstSession
val bobSession = testData.secondSession!!
@ -58,12 +58,12 @@ class PreShareKeysTest : InstrumentedTest {
Log.d("#Test", "Room Key Received from alice $preShareCount")
// Force presharing of new outbound key
mTestHelper.doSync<Unit> {
testHelper.doSync<Unit> {
aliceSession.cryptoService().prepareToEncrypt(e2eRoomID, it)
}
mTestHelper.waitWithLatch { latch ->
mTestHelper.retryPeriodicallyWithLatch(latch) {
testHelper.waitWithLatch { latch ->
testHelper.retryPeriodicallyWithLatch(latch) {
val newGossipCount = bobSession.cryptoService().getGossipingEvents().count {
it.senderId == aliceSession.myUserId &&
it.getClearType() == EventType.ROOM_KEY
@ -88,16 +88,16 @@ class PreShareKeysTest : InstrumentedTest {
assertEquals("The session received by bob should match what alice sent", 0, sharedIndex)
// Just send a real message as test
val sentEvent = mTestHelper.sendTextMessage(aliceSession.getRoom(e2eRoomID)!!, "Allo", 1).first()
val sentEvent = testHelper.sendTextMessage(aliceSession.getRoom(e2eRoomID)!!, "Allo", 1).first()
assertEquals(megolmSessionId, sentEvent.root.content.toModel<EncryptedEventContent>()?.sessionId, "Unexpected megolm session")
mTestHelper.waitWithLatch { latch ->
mTestHelper.retryPeriodicallyWithLatch(latch) {
testHelper.waitWithLatch { latch ->
testHelper.retryPeriodicallyWithLatch(latch) {
bobSession.getRoom(e2eRoomID)?.getTimeLineEvent(sentEvent.eventId)?.root?.getClearType() == EventType.MESSAGE
}
}
mTestHelper.signOutAndClose(aliceSession)
mTestHelper.signOutAndClose(bobSession)
testHelper.signOutAndClose(aliceSession)
testHelper.signOutAndClose(bobSession)
}
}

View File

@ -62,8 +62,8 @@ import kotlin.coroutines.resume
class UnwedgingTest : InstrumentedTest {
private lateinit var messagesReceivedByBob: List<TimelineEvent>
private val mTestHelper = CommonTestHelper(context())
private val mCryptoTestHelper = CryptoTestHelper(mTestHelper)
private val testHelper = CommonTestHelper(context())
private val cryptoTestHelper = CryptoTestHelper(testHelper)
@Before
fun init() {
@ -85,7 +85,7 @@ class UnwedgingTest : InstrumentedTest {
*/
@Test
fun testUnwedging() {
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
val aliceSession = cryptoTestData.firstSession
val aliceRoomId = cryptoTestData.roomId
@ -133,7 +133,7 @@ class UnwedgingTest : InstrumentedTest {
roomFromAlicePOV.sendTextMessage("First message")
// Wait for the message to be received by Bob
mTestHelper.await(latch)
testHelper.await(latch)
bobTimeline.removeListener(bobEventsListener)
messagesReceivedByBob.size shouldBe 1
@ -161,7 +161,7 @@ class UnwedgingTest : InstrumentedTest {
roomFromAlicePOV.sendTextMessage("Second message")
// Wait for the message to be received by Bob
mTestHelper.await(latch)
testHelper.await(latch)
bobTimeline.removeListener(bobEventsListener)
messagesReceivedByBob.size shouldBe 2
@ -179,7 +179,7 @@ class UnwedgingTest : InstrumentedTest {
aliceSession.cryptoService().discardOutboundSession(roomFromAlicePOV.roomId)
// Wait for the message to be received by Bob
mTestHelper.waitWithLatch {
testHelper.waitWithLatch {
bobEventsListener = createEventListener(it, 3)
bobTimeline.addListener(bobEventsListener)
messagesReceivedByBob = emptyList()
@ -201,11 +201,11 @@ class UnwedgingTest : InstrumentedTest {
Assert.assertEquals(EventType.MESSAGE, messagesReceivedByBob[1].root.getClearType())
Assert.assertEquals(EventType.MESSAGE, messagesReceivedByBob[2].root.getClearType())
// Bob Should not be able to decrypt last message, because session could not be sent as the olm channel was wedged
mTestHelper.await(bobFinalLatch)
testHelper.await(bobFinalLatch)
bobTimeline.removeListener(bobHasThreeDecryptedEventsListener)
// It's a trick to force key request on fail to decrypt
mTestHelper.doSync<Unit> {
testHelper.doSync<Unit> {
bobSession.cryptoService().crossSigningService()
.initializeCrossSigning(
object : UserInteractiveAuthInterceptor {
@ -222,8 +222,8 @@ class UnwedgingTest : InstrumentedTest {
}
// Wait until we received back the key
mTestHelper.waitWithLatch {
mTestHelper.retryPeriodicallyWithLatch(it) {
testHelper.waitWithLatch {
testHelper.retryPeriodicallyWithLatch(it) {
// we should get back the key and be able to decrypt
val result = tryOrNull {
bobSession.cryptoService().decryptEvent(messagesReceivedByBob[0].root, "")
@ -235,7 +235,7 @@ class UnwedgingTest : InstrumentedTest {
bobTimeline.dispose()
cryptoTestData.cleanUp(mTestHelper)
cryptoTestData.cleanUp(testHelper)
}
private fun createEventListener(latch: CountDownLatch, expectedNumberOfMessages: Int): Timeline.Listener {

View File

@ -45,14 +45,14 @@ import kotlin.coroutines.resume
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class XSigningTest : InstrumentedTest {
private val mTestHelper = CommonTestHelper(context())
private val mCryptoTestHelper = CryptoTestHelper(mTestHelper)
private val testHelper = CommonTestHelper(context())
private val cryptoTestHelper = CryptoTestHelper(testHelper)
@Test
fun test_InitializeAndStoreKeys() {
val aliceSession = mTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
val aliceSession = testHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
mTestHelper.doSync<Unit> {
testHelper.doSync<Unit> {
aliceSession.cryptoService().crossSigningService()
.initializeCrossSigning(object : UserInteractiveAuthInterceptor {
override fun performStage(flowResponse: RegistrationFlowResponse, errCode: String?, promise: Continuation<UIABaseAuth>) {
@ -79,12 +79,12 @@ class XSigningTest : InstrumentedTest {
assertTrue("Signing Keys should be trusted", aliceSession.cryptoService().crossSigningService().checkUserTrust(aliceSession.myUserId).isVerified())
mTestHelper.signOutAndClose(aliceSession)
testHelper.signOutAndClose(aliceSession)
}
@Test
fun test_CrossSigningCheckBobSeesTheKeys() {
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
val aliceSession = cryptoTestData.firstSession
val bobSession = cryptoTestData.secondSession
@ -98,21 +98,21 @@ class XSigningTest : InstrumentedTest {
password = TestConstants.PASSWORD
)
mTestHelper.doSync<Unit> {
testHelper.doSync<Unit> {
aliceSession.cryptoService().crossSigningService().initializeCrossSigning(object : UserInteractiveAuthInterceptor {
override fun performStage(flowResponse: RegistrationFlowResponse, errCode: String?, promise: Continuation<UIABaseAuth>) {
promise.resume(aliceAuthParams)
}
}, it)
}
mTestHelper.doSync<Unit> { bobSession.cryptoService().crossSigningService().initializeCrossSigning(object : UserInteractiveAuthInterceptor {
testHelper.doSync<Unit> { bobSession.cryptoService().crossSigningService().initializeCrossSigning(object : UserInteractiveAuthInterceptor {
override fun performStage(flowResponse: RegistrationFlowResponse, errCode: String?, promise: Continuation<UIABaseAuth>) {
promise.resume(bobAuthParams)
}
}, it) }
// Check that alice can see bob keys
mTestHelper.doSync<MXUsersDevicesMap<CryptoDeviceInfo>> { aliceSession.cryptoService().downloadKeys(listOf(bobSession.myUserId), true, it) }
testHelper.doSync<MXUsersDevicesMap<CryptoDeviceInfo>> { aliceSession.cryptoService().downloadKeys(listOf(bobSession.myUserId), true, it) }
val bobKeysFromAlicePOV = aliceSession.cryptoService().crossSigningService().getUserCrossSigningKeys(bobSession.myUserId)
assertNotNull("Alice can see bob Master key", bobKeysFromAlicePOV!!.masterKey())
@ -124,13 +124,13 @@ class XSigningTest : InstrumentedTest {
assertFalse("Bob keys from alice pov should not be trusted", bobKeysFromAlicePOV.isTrusted())
mTestHelper.signOutAndClose(aliceSession)
mTestHelper.signOutAndClose(bobSession)
testHelper.signOutAndClose(aliceSession)
testHelper.signOutAndClose(bobSession)
}
@Test
fun test_CrossSigningTestAliceTrustBobNewDevice() {
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
val aliceSession = cryptoTestData.firstSession
val bobSession = cryptoTestData.secondSession
@ -144,12 +144,12 @@ class XSigningTest : InstrumentedTest {
password = TestConstants.PASSWORD
)
mTestHelper.doSync<Unit> { aliceSession.cryptoService().crossSigningService().initializeCrossSigning(object : UserInteractiveAuthInterceptor {
testHelper.doSync<Unit> { aliceSession.cryptoService().crossSigningService().initializeCrossSigning(object : UserInteractiveAuthInterceptor {
override fun performStage(flowResponse: RegistrationFlowResponse, errCode: String?, promise: Continuation<UIABaseAuth>) {
promise.resume(aliceAuthParams)
}
}, it) }
mTestHelper.doSync<Unit> { bobSession.cryptoService().crossSigningService().initializeCrossSigning(object : UserInteractiveAuthInterceptor {
testHelper.doSync<Unit> { bobSession.cryptoService().crossSigningService().initializeCrossSigning(object : UserInteractiveAuthInterceptor {
override fun performStage(flowResponse: RegistrationFlowResponse, errCode: String?, promise: Continuation<UIABaseAuth>) {
promise.resume(bobAuthParams)
}
@ -157,21 +157,21 @@ class XSigningTest : InstrumentedTest {
// Check that alice can see bob keys
val bobUserId = bobSession.myUserId
mTestHelper.doSync<MXUsersDevicesMap<CryptoDeviceInfo>> { aliceSession.cryptoService().downloadKeys(listOf(bobUserId), true, it) }
testHelper.doSync<MXUsersDevicesMap<CryptoDeviceInfo>> { aliceSession.cryptoService().downloadKeys(listOf(bobUserId), true, it) }
val bobKeysFromAlicePOV = aliceSession.cryptoService().crossSigningService().getUserCrossSigningKeys(bobUserId)
assertTrue("Bob keys from alice pov should not be trusted", bobKeysFromAlicePOV?.isTrusted() == false)
mTestHelper.doSync<Unit> { aliceSession.cryptoService().crossSigningService().trustUser(bobUserId, it) }
testHelper.doSync<Unit> { aliceSession.cryptoService().crossSigningService().trustUser(bobUserId, it) }
// Now bobs logs in on a new device and verifies it
// We will want to test that in alice POV, this new device would be trusted by cross signing
val bobSession2 = mTestHelper.logIntoAccount(bobUserId, SessionTestParams(true))
val bobSession2 = testHelper.logIntoAccount(bobUserId, SessionTestParams(true))
val bobSecondDeviceId = bobSession2.sessionParams.deviceId!!
// Check that bob first session sees the new login
val data = mTestHelper.doSync<MXUsersDevicesMap<CryptoDeviceInfo>> {
val data = testHelper.doSync<MXUsersDevicesMap<CryptoDeviceInfo>> {
bobSession.cryptoService().downloadKeys(listOf(bobUserId), true, it)
}
@ -183,12 +183,12 @@ class XSigningTest : InstrumentedTest {
assertNotNull("Bob Second device should be known and persisted from first", bobSecondDevicePOVFirstDevice)
// Manually mark it as trusted from first session
mTestHelper.doSync<Unit> {
testHelper.doSync<Unit> {
bobSession.cryptoService().crossSigningService().trustDevice(bobSecondDeviceId, it)
}
// Now alice should cross trust bob's second device
val data2 = mTestHelper.doSync<MXUsersDevicesMap<CryptoDeviceInfo>> {
val data2 = testHelper.doSync<MXUsersDevicesMap<CryptoDeviceInfo>> {
aliceSession.cryptoService().downloadKeys(listOf(bobUserId), true, it)
}
@ -200,8 +200,8 @@ class XSigningTest : InstrumentedTest {
val result = aliceSession.cryptoService().crossSigningService().checkDeviceTrust(bobUserId, bobSecondDeviceId, null)
assertTrue("Bob second device should be trusted from alice POV", result.isCrossSignedVerified())
mTestHelper.signOutAndClose(aliceSession)
mTestHelper.signOutAndClose(bobSession)
mTestHelper.signOutAndClose(bobSession2)
testHelper.signOutAndClose(aliceSession)
testHelper.signOutAndClose(bobSession)
testHelper.signOutAndClose(bobSession2)
}
}

Some files were not shown because too many files have changed in this diff Show More