Merge branch 'release/1.3.2' into main

This commit is contained in:
Benoit Marty 2021-10-08 16:35:44 +02:00
commit 7b46796a81
802 changed files with 6057 additions and 3249 deletions

View File

@ -9,25 +9,6 @@ insert_final_newline=true
# it's automatically set to 100 on `ktlint --android ...` (per Android Kotlin Style Guide)
max_line_length=off
# Comma-separated list of rules to disable (Since 0.34.0)
# Note that rules in any ruleset other than the standard ruleset will need to be prefixed
# by the ruleset identifier.
disabled_rules=no-multi-spaces,colon-spacing,chain-wrapping,import-ordering,experimental:annotation
# The following (so far identified) rules are kept:
# no-blank-line-before-rbrace
# final-newline
# no-consecutive-blank-lines
# comment-spacing
# filename
# comma-spacing
# paren-spacing
# op-spacing
# string-template
# no-unused-imports
# curly-spacing
# no-semi
# no-empty-class-body
# experimental:multiline-if-else
# experimental:no-empty-first-line-in-method-block
# no-wildcard-imports
# From https://github.com/pinterest/ktlint#custom-ktlint-specific-editorconfig-properties
# default IntelliJ IDEA style, same as alphabetical, but with "java", "javax", "kotlin" and alias imports in the end of the imports list
ij_kotlin_imports_layout=*,java.**,javax.**,kotlin.**,^

View File

@ -23,12 +23,12 @@ body:
- type: textarea
id: result
attributes:
label: What happened?
label: Intended result and actual result
placeholder: Tell us what went wrong
value: |
### What did you expect?
#### What did you expect?
### What happened?
#### What happened instead?
validations:
required: true
- type: input

View File

@ -1,7 +1,7 @@
name: Release checklist
description: Checklist for each release. This template is only for the core team.
title: "[Release] Element Android v"
labels: [\U0001F680 Release]
labels: [🚀 Release]
assignees:
- bmarty

View File

@ -14,15 +14,19 @@ jobs:
- name: Run code quality check suite
run: ./tools/check/check_code_quality.sh
klint:
ktlint:
name: Kotlin Linter
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Run klint
- name: Run ktlint
run: |
curl -sSLO https://github.com/pinterest/ktlint/releases/download/0.36.0/ktlint && chmod a+x ktlint
./ktlint --android --experimental -v
./gradlew ktlintCheck --continue
- name: Upload reports
uses: actions/upload-artifact@v2
with:
name: ktlinting-report
path: vector/build/reports/ktlint/*.*
# Lint for main module and all the other modules
android-lint:

2
.gitignore vendored
View File

@ -16,4 +16,4 @@
/fastlane/private
/fastlane/report.xml
ktlint
/library/build

View File

@ -1,3 +1,49 @@
Changes in Element v1.3.2 (2021-10-08)
======================================
Features ✨
----------
- Android Auto notification support ([#240](https://github.com/vector-im/element-android/issues/240))
- Add a fallback for user displayName when this one is null or empty ([#3732](https://github.com/vector-im/element-android/issues/3732))
- Add client base url config to customize permalinks ([#4027](https://github.com/vector-im/element-android/issues/4027))
- Check if DM exists before creating a new one ([#4157](https://github.com/vector-im/element-android/issues/4157))
- Handle 8 new slash commands: `/ignore`, `/unignore`, `/roomname`, `/myroomnick`, `/roomavatar`, `/myroomavatar`, `/lenny`, `/whois`. ([#4158](https://github.com/vector-im/element-android/issues/4158))
- Display identity server policies in the Discovery screen ([#4184](https://github.com/vector-im/element-android/issues/4184))
Bugfixes 🐛
----------
- Ensure initial sync progress dialog is hidden when the initial sync is over ([#983](https://github.com/vector-im/element-android/issues/983))
- Avoid resending notifications that are already shown ([#1673](https://github.com/vector-im/element-android/issues/1673))
- Room filter no results bad CTA in space mode when a space selected ([#3048](https://github.com/vector-im/element-android/issues/3048))
- Fixes notifications not dismissing when reading messages on other devices ([#3347](https://github.com/vector-im/element-android/issues/3347))
- Fixes the passphrase screen being incorrectly shown when pressing back on the key verification screen.
When the user doesn't have a passphrase set we don't show the passphrase screen. ([#3898](https://github.com/vector-im/element-android/issues/3898))
- App doesn't take you to a Space after choosing to Join it ([#3933](https://github.com/vector-im/element-android/issues/3933))
- Validate public space addresses and room aliases length ([#3934](https://github.com/vector-im/element-android/issues/3934))
- Save button for adding rooms to a space is hidden when scrolling through list of rooms ([#3935](https://github.com/vector-im/element-android/issues/3935))
- Align new room encryption default to Web ([#4045](https://github.com/vector-im/element-android/issues/4045))
- Fix Reply/Edit mode animation is broken when sending ([#4077](https://github.com/vector-im/element-android/issues/4077))
- Added changes that will make SearchView in search bar focused by default on opening reaction picker.
When tapping close icon of SearchView, the SearchView did not collapse therefore added the on close listener
which will collapse the SearchView on close. ([#4092](https://github.com/vector-im/element-android/issues/4092))
- Troubleshoot notification: Fix button not clickable ([#4109](https://github.com/vector-im/element-android/issues/4109))
- Harmonize wording in the message bottom sheet and move up the View Reactions item ([#4155](https://github.com/vector-im/element-android/issues/4155))
- Remove unused SendRelationWorker and related API call (3588) ([#4156](https://github.com/vector-im/element-android/issues/4156))
- SIP user to native user mapping is wrong ([#4176](https://github.com/vector-im/element-android/issues/4176))
SDK API changes ⚠️
------------------
- Create extension `String.isMxcUrl()` ([#4158](https://github.com/vector-im/element-android/issues/4158))
Other changes
-------------
- Use ktlint plugin. See [the documentation](https://github.com/vector-im/element-android/blob/develop/CONTRIBUTING.md#ktlint) for more detail. ([#3957](https://github.com/vector-im/element-android/issues/3957))
- Minimize the use of exported="true" in android Manifest (link: https://github.com/matrix-org/matrix-dinsic/issues/618) ([#4018](https://github.com/vector-im/element-android/issues/4018))
- Fix redundancy in heading in the bug report issue form ([#4076](https://github.com/vector-im/element-android/issues/4076))
- Fix release label in the release issue template ([#4113](https://github.com/vector-im/element-android/issues/4113))
Changes in Element v1.3.1 (2021-09-29)
======================================

View File

@ -9,7 +9,7 @@ Android support can be found in this [![Element Android Matrix room #element-and
## Android Studio settings
Please set the "hard wrap" setting of Android Studio to 160 chars, this is the setting we use internally to format the source code (Menu `Settings/Editor/Code Style` then `Hard wrap at`).
Please ensure that your using the project formatting rules (which are in the project at .idea/codeStyles/), and format the file before committing them.
Please ensure that you're using the project formatting rules (which are in the project at .idea/codeStyles/), and format the file before committing them.
### Template
@ -80,14 +80,13 @@ Make sure the following commands execute without any error:
#### ktlint
<pre>
curl -sSLO https://github.com/pinterest/ktlint/releases/download/0.34.2/ktlint && chmod a+x ktlint
./ktlint --android --experimental -v
./gradlew ktlintCheck --continue
</pre>
Note that you can run
<pre>
./ktlint --android --experimental -v -F
./gradlew ktlintFormat
</pre>
For ktlint to fix some detected errors for you (you still have to check and commit the fix of course)

View File

@ -39,7 +39,6 @@ import androidx.core.view.updatePadding
import androidx.transition.TransitionManager
import androidx.viewpager2.widget.ViewPager2
import im.vector.lib.attachmentviewer.databinding.ActivityAttachmentViewerBinding
import java.lang.ref.WeakReference
import kotlin.math.abs
@ -291,8 +290,8 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi
private fun calculateTranslationAlpha(translationY: Float, translationLimit: Int): Float =
1.0f - 1.0f / translationLimit.toFloat() / 4f * abs(translationY)
private fun createSwipeToDismissHandler()
: SwipeToDismissHandler = SwipeToDismissHandler(
private fun createSwipeToDismissHandler(): SwipeToDismissHandler =
SwipeToDismissHandler(
swipeView = views.dismissContainer,
shouldAnimateDismiss = { shouldAnimateDismiss() },
onDismiss = { animateClose() },

View File

@ -36,8 +36,8 @@ interface ImageLoaderTarget {
fun onResourceReady(uid: String, resource: Drawable)
}
internal class DefaultImageLoaderTarget(val holder: AnimatedImageViewHolder, private val contextView: ImageView)
: ImageLoaderTarget {
internal class DefaultImageLoaderTarget(val holder: AnimatedImageViewHolder, private val contextView: ImageView) :
ImageLoaderTarget {
override fun contextView(): ImageView {
return contextView
}

View File

@ -27,7 +27,14 @@ buildscript {
}
}
// ktlint Plugin
plugins {
id "org.jlleitschuh.gradle.ktlint" version "10.2.0"
}
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
maven {
@ -75,6 +82,26 @@ allprojects {
// You can override by passing `-PallWarningsAsErrors=false` in the command line
kotlinOptions.allWarningsAsErrors = project.getProperties().getOrDefault("allWarningsAsErrors", "true").toBoolean()
}
// Fix "Java heap space" issue
tasks.withType(org.jlleitschuh.gradle.ktlint.tasks.BaseKtLintCheckTask).configureEach {
it.workerMaxHeapSize.set("2G")
}
// See https://github.com/JLLeitschuh/ktlint-gradle#configuration
ktlint {
android = true
ignoreFailures = false
enableExperimentalRules = true
// display the corresponding rule
verbose = true
disabledRules = [
"spacing-between-declarations-with-comments",
"no-multi-spaces",
"experimental:spacing-between-declarations-with-annotations",
"experimental:annotation"
]
}
}
task clean(type: Delete) {

View File

@ -9,9 +9,9 @@ ext.versions = [
def gradle = "7.0.2"
// Ref: https://kotlinlang.org/releases.html
def kotlin = "1.5.30"
def kotlinCoroutines = "1.5.1"
def dagger = "2.38.1"
def kotlin = "1.5.31"
def kotlinCoroutines = "1.5.2"
def dagger = "2.39.1"
def retrofit = "2.9.0"
def arrow = "0.8.2"
def markwon = "4.6.2"
@ -49,7 +49,7 @@ ext.libs = [
'exifinterface' : "androidx.exifinterface:exifinterface:1.3.3",
'fragmentKtx' : "androidx.fragment:fragment-ktx:1.3.6",
'constraintLayout' : "androidx.constraintlayout:constraintlayout:2.1.1",
'work' : "androidx.work:work-runtime-ktx:2.5.0",
'work' : "androidx.work:work-runtime-ktx:2.6.0",
'autoFill' : "androidx.autofill:autofill:1.1.0",
'preferenceKtx' : "androidx.preference:preference-ktx:1.1.1",
'junit' : "androidx.test.ext:junit:1.1.3",

View File

@ -0,0 +1,2 @@
Hlavní změny v této verzi: Uspořádejte si místnosti pomocí Prostorů!
Úplný seznam změn: https://github.com/vector-im/element-android/releases/tag/v1.3.0

View File

@ -0,0 +1,2 @@
Main changes in this version: Add support for Android Auto. Lot of bug fixes!
Full changelog: https://github.com/vector-im/element-android/releases/tag/v1.3.2

View File

@ -0,0 +1,2 @@
Põhilised muutused selles versioonis: halda oma jututubasid koondades neid uut tüüpi kogukondadesse!
Kogu ingliskeelne muudatuste logi: https://github.com/vector-im/element-android/releases/tag/v1.3.0

View File

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

View File

@ -1,2 +1,2 @@
Principaux changements pour cette version : messages vocaux activés par défault.
Intégralité des changements : https://github.com/vector-im/element-android/releases/tag/v1.1.16
Principaux changements pour cette version : messages vocaux activés par défaut.
Intégralité des changements : https://github.com/vector-im/element-android/releases/tag/v1.2.0

View File

@ -0,0 +1,2 @@
Principaux changements pour cette version : Beaucoup daméliorations sur la VoIP et les Espaces (toujours en bêta).
Intégralité des changements : https://github.com/vector-im/element-android/releases/tag/v1.2.1

View File

@ -0,0 +1,2 @@
Principaux changements pour cette version : Organisez vous salons à laide des Espaces !
Intégralité des changements : https://github.com/vector-im/element-android/releases/tag/v1.3.0

View File

@ -0,0 +1,2 @@
Fő változás ebben a verzióban: Szobák terekbe szervezése
Teljes változásnapló: https://github.com/vector-im/element-android/releases/tag/v1.3.0

View File

@ -1,2 +1,2 @@
Perubahan utama dalam versi ini: Pesan Suara diaktifkan secara default
Changelog lanjutan: https://github.com/vector-im/element-android/releases/tag/v1.1.16
Changelog lanjutan: https://github.com/vector-im/element-android/releases/tag/v1.2.0

View File

@ -0,0 +1,2 @@
Perubahan utama di versi ini: Banyak perbaikan di VoIP dan Space (masih beta).
Changelog lanjutan: https://github.com/vector-im/element-android/releases/tag/v1.2.1

View File

@ -0,0 +1,2 @@
Perubahan utama di versi ini: Organisir ruangan Anda menggunakan sebuah Space!
Changelog lanjutan: https://github.com/vector-im/element-android/releases/tag/v1.3.0

View File

@ -11,7 +11,7 @@ Element adalah perpesanan yang aman dan aplikasi kolaborasi tim produktivitas ya
Element benar-benar berbeda dari aplikasi perpesanan dan kolaborasi lainnya. Element beroperasi pada Matrix, jaringan terbuka untuk pengiriman pesan yang aman dan komunikasi terdesentralisasi. Matrix memungkinkan hosting sendiri untuk memberi pengguna kepemilikan maksimum dan kontrol data dan pesan mereka.
<b>Pesan privasi dan terenkripsi</b>
Element melindungi Anda dari iklan yang tidak diinginkan, data penambangan dan taman berdinding. Element juga mengamankan semua data Anda, komunikasi video dan suara satu-ke-satu melalui enkripsi ujung-ke-ujung dan verifikasi perangkat yang ditanda tangani silang.
Element melindungi Anda dari iklan yang tidak diinginkan, penambangan data dan taman berdinding. Element juga mengamankan semua data Anda, komunikasi video dan suara satu-ke-satu melalui enkripsi ujung-ke-ujung dan verifikasi perangkat yang ditandatangani secara silang.
Element memberi Anda kendali atas privasi Anda sambil memungkinkan Anda untuk berkomunikasi dengan aman dengan siapa pun di jaringan Matrix, atau alat kolaborasi bisnis lainnya dengan mengintegrasikan dengan aplikasi seperti Slack.

View File

@ -0,0 +1,2 @@
Modifiche principali in questa versione: organizza le tue stanze usando gli Spazi!
Cronologia completa: https://github.com/vector-im/element-android/releases/tag/v1.3.0

View File

@ -0,0 +1,2 @@
Principais mudanças nesta versão: Organize suas salas usando Espaços!
Changelog completo: https://github.com/vector-im/element-android/releases/tag/v1.3.0

View File

@ -0,0 +1,2 @@
Ndryshime kryesore në këtë version: Sistemoni dhomat tuaja duke përdorur Hapësira!
Regjistër i plotë ndryshimesh: https://github.com/vector-im/element-android/releases/tag/v1.3.0

View File

@ -0,0 +1,2 @@
Huvudsakliga ändringar i den här versionen: Många förbättringar för VoIP och utrymmen (fortfarande i beta).
Full ändringslogg: https://github.com/vector-im/element-android/releases/tag/v1.2.1

View File

@ -0,0 +1,2 @@
Huvudsakliga ändringar i den här versionen: Organisera dina rum med utrymmen!
Full ändringslogg: https://github.com/vector-im/element-android/releases/tag/v1.3.0

View File

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

View File

@ -0,0 +1,2 @@
此版本主要更改:使用空间组织你的聊天室!
完整更新日志https://github.com/vector-im/element-android/releases/tag/v1.3.0

View File

@ -0,0 +1,2 @@
此版本中的主要變動:使用空間來整理您的聊天室!
完整的變更紀錄https://github.com/vector-im/element-android/releases/tag/v1.3.0

View File

@ -34,8 +34,8 @@ private class LiveDataObservable<T>(
liveData.observeForever(relay)
}
private inner class RemoveObserverInMainThread(private val observer: io.reactivex.Observer<in T>)
: MainThreadDisposable(), Observer<T> {
private inner class RemoveObserverInMainThread(private val observer: io.reactivex.Observer<in T>) :
MainThreadDisposable(), Observer<T> {
override fun onChanged(t: T?) {
if (!isDisposed) {

View File

@ -16,8 +16,8 @@
package org.matrix.android.sdk.rx
import org.matrix.android.sdk.api.util.Optional
import io.reactivex.Observable
import org.matrix.android.sdk.api.util.Optional
fun <T : Any> Observable<Optional<T>>.unwrap(): Observable<T> {
return filter { it.hasValue() }.map { it.get() }

View File

@ -31,7 +31,7 @@ android {
// that the app's state is completely cleared between tests.
testInstrumentationRunnerArguments clearPackageData: 'true'
buildConfigField "String", "SDK_VERSION", "\"1.3.1\""
buildConfigField "String", "SDK_VERSION", "\"1.3.2\""
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.1"))
implementation(platform("com.squareup.okhttp3:okhttp-bom:4.9.2"))
implementation 'com.squareup.okhttp3:okhttp'
implementation 'com.squareup.okhttp3:logging-interceptor'
implementation 'com.squareup.okhttp3:okhttp-urlconnection'
@ -154,7 +154,7 @@ dependencies {
implementation 'com.otaliastudios:transcoder:0.10.4'
// Phone number https://github.com/google/libphonenumber
implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.33'
implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.34'
testImplementation libs.tests.junit
testImplementation 'org.robolectric:robolectric:4.6.1'

View File

@ -8,10 +8,15 @@
This is mandatory to run integration tests
-->
<provider
android:name="androidx.work.impl.WorkManagerInitializer"
android:authorities="${applicationId}.workmanager-init"
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:node="merge">
<meta-data
android:name="androidx.work.WorkManagerInitializer"
android:value="androidx.startup"
tools:node="remove" />
</provider>
</application>

View File

@ -18,8 +18,8 @@ package org.matrix.android.sdk
import android.content.Context
import androidx.test.core.app.ApplicationProvider
import org.matrix.android.sdk.test.shared.createTimberTestRule
import org.junit.Rule
import org.matrix.android.sdk.test.shared.createTimberTestRule
interface InstrumentedTest {

View File

@ -16,9 +16,9 @@
package org.matrix.android.sdk
import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.asCoroutineDispatcher
import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers
import java.util.concurrent.Executors
internal val testCoroutineDispatchers = MatrixCoroutineDispatchers(Main, Main, Main, Main,

View File

@ -16,16 +16,16 @@
package org.matrix.android.sdk.account
import org.matrix.android.sdk.InstrumentedTest
import org.matrix.android.sdk.common.CommonTestHelper
import org.matrix.android.sdk.common.CryptoTestHelper
import org.matrix.android.sdk.common.SessionTestParams
import org.matrix.android.sdk.common.TestConstants
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import org.junit.runners.MethodSorters
import org.matrix.android.sdk.InstrumentedTest
import org.matrix.android.sdk.common.CommonTestHelper
import org.matrix.android.sdk.common.CryptoTestHelper
import org.matrix.android.sdk.common.SessionTestParams
import org.matrix.android.sdk.common.TestConstants
@RunWith(JUnit4::class)
@FixMethodOrder(MethodSorters.JVM)

View File

@ -16,17 +16,17 @@
package org.matrix.android.sdk.account
import org.matrix.android.sdk.InstrumentedTest
import org.matrix.android.sdk.api.failure.isInvalidPassword
import org.matrix.android.sdk.common.CommonTestHelper
import org.matrix.android.sdk.common.SessionTestParams
import org.matrix.android.sdk.common.TestConstants
import org.amshove.kluent.shouldBeTrue
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import org.junit.runners.MethodSorters
import org.matrix.android.sdk.InstrumentedTest
import org.matrix.android.sdk.api.failure.isInvalidPassword
import org.matrix.android.sdk.common.CommonTestHelper
import org.matrix.android.sdk.common.SessionTestParams
import org.matrix.android.sdk.common.TestConstants
@RunWith(JUnit4::class)
@FixMethodOrder(MethodSorters.JVM)

View File

@ -67,9 +67,9 @@ class DeactivateAccountTest : InstrumentedTest {
val throwable = commonTestHelper.logAccountWithError(session.myUserId, TestConstants.PASSWORD)
// Test the error
assertTrue(throwable is Failure.ServerError
&& throwable.error.code == MatrixError.M_USER_DEACTIVATED
&& throwable.error.message == "This account has been deactivated")
assertTrue(throwable is Failure.ServerError &&
throwable.error.code == MatrixError.M_USER_DEACTIVATED &&
throwable.error.message == "This account has been deactivated")
// Try to create an account with the deactivate account user id, it will fail (M_USER_IN_USE)
val hs = commonTestHelper.createHomeServerConfig()
@ -95,8 +95,8 @@ class DeactivateAccountTest : InstrumentedTest {
// Test the error
accountCreationError.let {
assertTrue(it is Failure.ServerError
&& it.error.code == MatrixError.M_USER_IN_USE)
assertTrue(it is Failure.ServerError &&
it.error.code == MatrixError.M_USER_IN_USE)
}
// No need to close the session, it has been deactivated

View File

@ -15,12 +15,12 @@
*/
package org.matrix.android.sdk.common
import org.matrix.android.sdk.internal.session.TestInterceptor
import okhttp3.Interceptor
import okhttp3.Protocol
import okhttp3.Request
import okhttp3.Response
import okhttp3.ResponseBody.Companion.toResponseBody
import org.matrix.android.sdk.internal.session.TestInterceptor
import javax.net.ssl.HttpsURLConnection
/**

View File

@ -17,8 +17,8 @@
package org.matrix.android.sdk.common
import androidx.annotation.CallSuper
import org.matrix.android.sdk.api.MatrixCallback
import org.junit.Assert.fail
import org.matrix.android.sdk.api.MatrixCallback
import timber.log.Timber
import java.util.concurrent.CountDownLatch

View File

@ -26,9 +26,9 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.matrix.android.sdk.internal.crypto.attachments.MXEncryptedAttachments
import org.matrix.android.sdk.internal.crypto.attachments.toElementToDecrypt
import org.matrix.android.sdk.internal.crypto.model.rest.EncryptedFileInfo
import org.matrix.android.sdk.internal.crypto.model.rest.EncryptedFileKey
import org.matrix.android.sdk.internal.crypto.attachments.toElementToDecrypt
import java.io.ByteArrayOutputStream
import java.io.InputStream

View File

@ -16,12 +16,12 @@
package org.matrix.android.sdk.internal.crypto
import io.realm.RealmConfiguration
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
import org.matrix.android.sdk.internal.crypto.store.db.RealmCryptoStore
import org.matrix.android.sdk.internal.crypto.store.db.RealmCryptoStoreModule
import org.matrix.android.sdk.internal.crypto.store.db.mapper.CrossSigningKeysMapper
import org.matrix.android.sdk.internal.di.MoshiProvider
import io.realm.RealmConfiguration
import kotlin.random.Random
internal class CryptoStoreHelper {

View File

@ -17,9 +17,6 @@
package org.matrix.android.sdk.internal.crypto
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.matrix.android.sdk.InstrumentedTest
import org.matrix.android.sdk.internal.crypto.model.OlmSessionWrapper
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
import io.realm.Realm
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotEquals
@ -27,6 +24,9 @@ import org.junit.Assert.assertNull
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.matrix.android.sdk.InstrumentedTest
import org.matrix.android.sdk.internal.crypto.model.OlmSessionWrapper
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
import org.matrix.olm.OlmAccount
import org.matrix.olm.OlmManager
import org.matrix.olm.OlmSession

View File

@ -50,8 +50,8 @@ class PreShareKeysTest : InstrumentedTest {
aliceSession.cryptoService().discardOutboundSession(e2eRoomID)
val preShareCount = bobSession.cryptoService().getGossipingEvents().count {
it.senderId == aliceSession.myUserId
&& it.getClearType() == EventType.ROOM_KEY
it.senderId == aliceSession.myUserId &&
it.getClearType() == EventType.ROOM_KEY
}
assertEquals("Bob should not have receive any key from alice at this point", 0, preShareCount)
@ -65,16 +65,16 @@ class PreShareKeysTest : InstrumentedTest {
mTestHelper.waitWithLatch { latch ->
mTestHelper.retryPeriodicallyWithLatch(latch) {
val newGossipCount = bobSession.cryptoService().getGossipingEvents().count {
it.senderId == aliceSession.myUserId
&& it.getClearType() == EventType.ROOM_KEY
it.senderId == aliceSession.myUserId &&
it.getClearType() == EventType.ROOM_KEY
}
newGossipCount > preShareCount
}
}
val latest = bobSession.cryptoService().getGossipingEvents().lastOrNull {
it.senderId == aliceSession.myUserId
&& it.getClearType() == EventType.ROOM_KEY
it.senderId == aliceSession.myUserId &&
it.getClearType() == EventType.ROOM_KEY
}
val content = latest?.getClearContent().toModel<RoomKeyContent>()

View File

@ -18,6 +18,11 @@ package org.matrix.android.sdk.internal.crypto.gossiping
import android.util.Log
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Assert
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.matrix.android.sdk.InstrumentedTest
import org.matrix.android.sdk.api.NoOpMatrixCallback
import org.matrix.android.sdk.api.extensions.tryOrNull
@ -31,11 +36,6 @@ import org.matrix.android.sdk.common.SessionTestParams
import org.matrix.android.sdk.common.TestConstants
import org.matrix.android.sdk.internal.crypto.model.event.EncryptedEventContent
import org.matrix.android.sdk.internal.crypto.model.event.WithHeldCode
import org.junit.Assert
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@RunWith(AndroidJUnit4::class)
@FixMethodOrder(MethodSorters.JVM)

View File

@ -17,9 +17,6 @@
package org.matrix.android.sdk.internal.crypto.keysbackup
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.matrix.android.sdk.InstrumentedTest
import org.matrix.android.sdk.api.listeners.ProgressListener
import org.matrix.android.sdk.common.assertByteArrayNotEqual
import org.junit.Assert.assertArrayEquals
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
@ -28,6 +25,9 @@ import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.matrix.android.sdk.InstrumentedTest
import org.matrix.android.sdk.api.listeners.ProgressListener
import org.matrix.android.sdk.common.assertByteArrayNotEqual
import org.matrix.olm.OlmManager
import org.matrix.olm.OlmPkDecryption

View File

@ -17,6 +17,16 @@
package org.matrix.android.sdk.internal.crypto.keysbackup
import androidx.test.ext.junit.runners.AndroidJUnit4
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.Assert.fail
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.matrix.android.sdk.InstrumentedTest
import org.matrix.android.sdk.api.listeners.ProgressListener
import org.matrix.android.sdk.api.listeners.StepProgressListener
@ -33,16 +43,6 @@ import org.matrix.android.sdk.internal.crypto.keysbackup.model.MegolmBackupCreat
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysVersion
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysVersionResult
import org.matrix.android.sdk.internal.crypto.model.ImportRoomKeysResult
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.Assert.fail
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import java.util.ArrayList
import java.util.Collections
import java.util.concurrent.CountDownLatch

View File

@ -16,6 +16,7 @@
package org.matrix.android.sdk.internal.crypto.keysbackup
import org.junit.Assert
import org.matrix.android.sdk.api.listeners.ProgressListener
import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupService
@ -28,7 +29,6 @@ import org.matrix.android.sdk.common.assertListEquals
import org.matrix.android.sdk.internal.crypto.MegolmSessionData
import org.matrix.android.sdk.internal.crypto.keysbackup.model.MegolmBackupCreationInfo
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysVersion
import org.junit.Assert
import java.util.concurrent.CountDownLatch
class KeysBackupTestHelper(

View File

@ -16,11 +16,11 @@
package org.matrix.android.sdk.internal.crypto.keysbackup
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNull
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupService
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupState
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupStateListener
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNull
import java.util.concurrent.CountDownLatch
/**
@ -91,8 +91,8 @@ internal class StateObserver(private val keysBackup: KeysBackupService,
stateList.add(newState)
// Check that state transition is valid
if (stateList.size >= 2
&& !allowedStateTransitions.contains(stateList[stateList.size - 2] to newState)) {
if (stateList.size >= 2 &&
!allowedStateTransitions.contains(stateList[stateList.size - 2] to newState)) {
// Forbidden transition detected
lastTransitionError = "Forbidden transition detected from " + stateList[stateList.size - 2] + " to " + newState
}

View File

@ -18,8 +18,20 @@ package org.matrix.android.sdk.internal.crypto.ssss
import androidx.lifecycle.Observer
import androidx.test.ext.junit.runners.AndroidJUnit4
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
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.matrix.android.sdk.InstrumentedTest
import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.accountdata.UserAccountDataEvent
import org.matrix.android.sdk.api.session.securestorage.EncryptedSecretContent
import org.matrix.android.sdk.api.session.securestorage.KeySigner
import org.matrix.android.sdk.api.session.securestorage.RawBytesKeySpec
@ -33,18 +45,6 @@ import org.matrix.android.sdk.common.TestConstants
import org.matrix.android.sdk.internal.crypto.SSSS_ALGORITHM_AES_HMAC_SHA2
import org.matrix.android.sdk.internal.crypto.crosssigning.toBase64NoPadding
import org.matrix.android.sdk.internal.crypto.secrets.DefaultSharedSecretStorageService
import org.matrix.android.sdk.api.session.accountdata.UserAccountDataEvent
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
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import java.util.concurrent.CountDownLatch
@RunWith(AndroidJUnit4::class)

View File

@ -18,6 +18,16 @@ package org.matrix.android.sdk.internal.crypto.verification
import android.util.Log
import androidx.test.ext.junit.runners.AndroidJUnit4
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.Assert.fail
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.matrix.android.sdk.InstrumentedTest
import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.crypto.verification.CancelCode
@ -38,16 +48,6 @@ import org.matrix.android.sdk.internal.crypto.model.MXUsersDevicesMap
import org.matrix.android.sdk.internal.crypto.model.rest.KeyVerificationCancel
import org.matrix.android.sdk.internal.crypto.model.rest.KeyVerificationStart
import org.matrix.android.sdk.internal.crypto.model.rest.toValue
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.Assert.fail
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import java.util.concurrent.CountDownLatch
@RunWith(AndroidJUnit4::class)

View File

@ -17,13 +17,13 @@
package org.matrix.android.sdk.internal.crypto.verification.qrcode
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.matrix.android.sdk.InstrumentedTest
import org.amshove.kluent.shouldBe
import org.amshove.kluent.shouldNotBeEqualTo
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.matrix.android.sdk.InstrumentedTest
@RunWith(AndroidJUnit4::class)
@FixMethodOrder(MethodSorters.JVM)

View File

@ -25,6 +25,9 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.matrix.android.sdk.InstrumentedTest
import org.matrix.android.sdk.api.MatrixConfiguration
import org.matrix.android.sdk.common.TestRoomDisplayNameFallbackProvider
import org.matrix.android.sdk.internal.session.displayname.DisplayNameResolver
import org.matrix.android.sdk.internal.session.room.send.pills.MentionLinkSpecComparator
import org.matrix.android.sdk.internal.session.room.send.pills.TextPillsUtils
@ -48,7 +51,14 @@ class MarkdownParserTest : InstrumentedTest {
private val markdownParser = MarkdownParser(
Parser.builder().build(),
HtmlRenderer.builder().softbreak("<br />").build(),
TextPillsUtils(MentionLinkSpecComparator())
TextPillsUtils(
MentionLinkSpecComparator(),
DisplayNameResolver(
MatrixConfiguration(
applicationFlavor = "TestFlavor",
roomDisplayNameFallbackProvider = TestRoomDisplayNameFallbackProvider()
)
))
)
@Test

View File

@ -17,10 +17,10 @@
package org.matrix.android.sdk.internal.util
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.matrix.android.sdk.InstrumentedTest
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
import org.matrix.android.sdk.InstrumentedTest
@RunWith(AndroidJUnit4::class)
internal class JsonCanonicalizerTest : InstrumentedTest {

View File

@ -16,6 +16,14 @@
package org.matrix.android.sdk.session.room.timeline
import org.amshove.kluent.shouldBeFalse
import org.amshove.kluent.shouldBeTrue
import org.junit.Assert.assertTrue
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import org.junit.runners.MethodSorters
import org.matrix.android.sdk.InstrumentedTest
import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.session.events.model.EventType
@ -26,14 +34,6 @@ import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings
import org.matrix.android.sdk.common.CommonTestHelper
import org.matrix.android.sdk.common.CryptoTestHelper
import org.matrix.android.sdk.common.checkSendOrder
import org.amshove.kluent.shouldBeFalse
import org.amshove.kluent.shouldBeTrue
import org.junit.Assert.assertTrue
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import org.junit.runners.MethodSorters
import timber.log.Timber
import java.util.concurrent.CountDownLatch
@ -111,8 +111,8 @@ class TimelineBackToPreviousLastForwardTest : InstrumentedTest {
}
// Ok, we have the 10 last messages from Alice.
snapshot.size == 10
&& snapshot.all { it.root.content.toModel<MessageContent>()?.body?.startsWith(messageRoot).orFalse() }
snapshot.size == 10 &&
snapshot.all { it.root.content.toModel<MessageContent>()?.body?.startsWith(messageRoot).orFalse() }
}
bobTimeline.addListener(eventsListener)
@ -160,10 +160,10 @@ class TimelineBackToPreviousLastForwardTest : InstrumentedTest {
}
// Bob can see the first event of the room (so Back pagination has worked)
snapshot.lastOrNull()?.root?.getClearType() == EventType.STATE_ROOM_CREATE
snapshot.lastOrNull()?.root?.getClearType() == EventType.STATE_ROOM_CREATE &&
// 8 for room creation item, and 30 for the forward pagination
&& snapshot.size == 38
&& snapshot.checkSendOrder(messageRoot, 30, 0)
snapshot.size == 38 &&
snapshot.checkSendOrder(messageRoot, 30, 0)
}
bobTimeline.addListener(eventsListener)

View File

@ -16,6 +16,13 @@
package org.matrix.android.sdk.session.room.timeline
import org.amshove.kluent.shouldBeFalse
import org.amshove.kluent.shouldBeTrue
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import org.junit.runners.MethodSorters
import org.matrix.android.sdk.InstrumentedTest
import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.session.events.model.EventType
@ -26,13 +33,6 @@ import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings
import org.matrix.android.sdk.common.CommonTestHelper
import org.matrix.android.sdk.common.CryptoTestHelper
import org.matrix.android.sdk.common.checkSendOrder
import org.amshove.kluent.shouldBeFalse
import org.amshove.kluent.shouldBeTrue
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import org.junit.runners.MethodSorters
import timber.log.Timber
import java.util.concurrent.CountDownLatch
@ -86,8 +86,8 @@ class TimelineForwardPaginationTest : InstrumentedTest {
}
// Ok, we have the 10 last messages of the initial sync
snapshot.size == 10
&& snapshot.all { it.root.content.toModel<MessageContent>()?.body?.startsWith(message).orFalse() }
snapshot.size == 10 &&
snapshot.all { it.root.content.toModel<MessageContent>()?.body?.startsWith(message).orFalse() }
}
// Open the timeline at last sent message
@ -110,8 +110,8 @@ class TimelineForwardPaginationTest : InstrumentedTest {
}
// The event is not in db, so it is fetch alone
snapshot.size == 1
&& snapshot.all { it.root.content.toModel<MessageContent>()?.body?.startsWith("Message from Alice").orFalse() }
snapshot.size == 1 &&
snapshot.all { it.root.content.toModel<MessageContent>()?.body?.startsWith("Message from Alice").orFalse() }
}
aliceTimeline.addListener(aliceEventsListener)
@ -137,9 +137,9 @@ class TimelineForwardPaginationTest : InstrumentedTest {
}
// Alice can see the first event of the room (so Back pagination has worked)
snapshot.lastOrNull()?.root?.getClearType() == EventType.STATE_ROOM_CREATE
snapshot.lastOrNull()?.root?.getClearType() == EventType.STATE_ROOM_CREATE &&
// 6 for room creation item (backward pagination), 1 for the context, and 50 for the forward pagination
&& snapshot.size == 57 // 6 + 1 + 50
snapshot.size == 57 // 6 + 1 + 50
}
aliceTimeline.addListener(aliceEventsListener)
@ -166,8 +166,8 @@ class TimelineForwardPaginationTest : InstrumentedTest {
Timber.w(" event ${it.root.content}")
}
// 6 for room creation item (backward pagination),and numberOfMessagesToSend (all the message of the room)
snapshot.size == 6 + numberOfMessagesToSend
&& snapshot.checkSendOrder(message, numberOfMessagesToSend, 0)
snapshot.size == 6 + numberOfMessagesToSend &&
snapshot.checkSendOrder(message, numberOfMessagesToSend, 0)
}
aliceTimeline.addListener(aliceEventsListener)

View File

@ -16,6 +16,13 @@
package org.matrix.android.sdk.session.room.timeline
import org.amshove.kluent.shouldBeFalse
import org.amshove.kluent.shouldBeTrue
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import org.junit.runners.MethodSorters
import org.matrix.android.sdk.InstrumentedTest
import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.session.events.model.EventType
@ -26,13 +33,6 @@ import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings
import org.matrix.android.sdk.common.CommonTestHelper
import org.matrix.android.sdk.common.CryptoTestHelper
import org.matrix.android.sdk.common.checkSendOrder
import org.amshove.kluent.shouldBeFalse
import org.amshove.kluent.shouldBeTrue
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import org.junit.runners.MethodSorters
import timber.log.Timber
import java.util.concurrent.CountDownLatch
@ -107,8 +107,8 @@ class TimelinePreviousLastForwardTest : InstrumentedTest {
}
// Ok, we have the 10 last messages from Alice. This will be our future previous lastForward chunk
snapshot.size == 10
&& snapshot.all { it.root.content.toModel<MessageContent>()?.body?.startsWith(firstMessage).orFalse() }
snapshot.size == 10 &&
snapshot.all { it.root.content.toModel<MessageContent>()?.body?.startsWith(firstMessage).orFalse() }
}
bobTimeline.addListener(eventsListener)
@ -141,8 +141,8 @@ class TimelinePreviousLastForwardTest : InstrumentedTest {
}
// Ok, we have the 10 last messages from Alice. This will be our future previous lastForward chunk
snapshot.size == 10
&& snapshot.all { it.root.content.toModel<MessageContent>()?.body?.startsWith(secondMessage).orFalse() }
snapshot.size == 10 &&
snapshot.all { it.root.content.toModel<MessageContent>()?.body?.startsWith(secondMessage).orFalse() }
}
bobTimeline.addListener(eventsListener)
@ -216,11 +216,11 @@ class TimelinePreviousLastForwardTest : InstrumentedTest {
}
// Bob can see the first event of the room (so Back pagination has worked)
snapshot.lastOrNull()?.root?.getClearType() == EventType.STATE_ROOM_CREATE
snapshot.lastOrNull()?.root?.getClearType() == EventType.STATE_ROOM_CREATE &&
// 8 for room creation item 60 message from Alice
&& snapshot.size == 68 // 8 + 60
&& snapshot.checkSendOrder(secondMessage, 30, 0)
&& snapshot.checkSendOrder(firstMessage, 30, 30)
snapshot.size == 68 && // 8 + 60
snapshot.checkSendOrder(secondMessage, 30, 0) &&
snapshot.checkSendOrder(firstMessage, 30, 30)
}
bobTimeline.addListener(eventsListener)

View File

@ -17,10 +17,10 @@
package org.matrix.android.sdk.internal.network.interceptors
import org.matrix.android.sdk.internal.di.MatrixScope
import okhttp3.Interceptor
import okhttp3.Response
import okio.Buffer
import org.matrix.android.sdk.internal.di.MatrixScope
import timber.log.Timber
import java.io.IOException
import java.nio.charset.Charset
@ -36,8 +36,8 @@ import javax.inject.Inject
* non-production environment.
*/
@MatrixScope
internal class CurlLoggingInterceptor @Inject constructor()
: Interceptor {
internal class CurlLoggingInterceptor @Inject constructor() :
Interceptor {
/**
* Set any additional curl command options (see 'curl --help').
@ -90,8 +90,8 @@ internal class CurlLoggingInterceptor @Inject constructor()
curlCmd += ((if (compressed) " --compressed " else " ") + "'" + request.url.toString()
// Replace localhost for emulator by localhost for shell
.replace("://10.0.2.2:8080/".toRegex(), "://127.0.0.1:8080/")
+ "'")
.replace("://10.0.2.2:8080/".toRegex(), "://127.0.0.1:8080/") +
"'")
// Add Json formatting
curlCmd += " | python -m json.tool"

View File

@ -32,14 +32,26 @@ data class MatrixConfiguration(
"https://scalar-staging.riot.im/scalar/api"
),
/**
* Optional proxy to connect to the matrix servers
* You can create one using for instance Proxy(proxyType, InetSocketAddress.createUnresolved(hostname, port)
* Optional base url to create client permalinks (eg. https://www.example.com/#/) instead of Matrix ones (matrix.to links).
* Do not forget to add the "#" which is required by the permalink parser.
*
* Note: this field is only used for permalinks creation, you will also have to edit the string-array `permalink_supported_hosts` in the config file
* and add it to your manifest to handle these links in the application.
*/
val clientPermalinkBaseUrl: String? = null,
/**
* Optional proxy to connect to the matrix servers.
* You can create one using for instance Proxy(proxyType, InetSocketAddress.createUnresolved(hostname, port).
*/
val proxy: Proxy? = null,
/**
* True to advertise support for call transfers to other parties on Matrix calls.
*/
val supportsCallTransfer: Boolean = false,
/**
* MatrixItemDisplayNameFallbackProvider to provide default display name for MatrixItem. By default, the id will be used
*/
val matrixItemDisplayNameFallbackProvider: MatrixItemDisplayNameFallbackProvider? = null,
/**
* RoomDisplayNameFallbackProvider to provide default room display name.
*/
@ -47,7 +59,7 @@ data class MatrixConfiguration(
) {
/**
* Can be implemented by your Application class
* Can be implemented by your Application class.
*/
interface Provider {
fun providesMatrixConfiguration(): MatrixConfiguration

View File

@ -0,0 +1,34 @@
/*
* Copyright (c) 2021 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.api
/**
* This object define some global constants regarding the Matrix specification
*/
object MatrixConstants {
/**
* Max length for an alias. Room aliases MUST NOT exceed 255 bytes (including the # sigil and the domain).
* See [maxAliasLocalPartLength]
* Ref. https://matrix.org/docs/spec/appendices#room-aliases
*/
const val ALIAS_MAX_LENGTH = 255
fun maxAliasLocalPartLength(domain: String): Int {
return (ALIAS_MAX_LENGTH - 1 /* # sigil */ - 1 /* ':' */ - domain.length)
.coerceAtLeast(0)
}
}

View File

@ -0,0 +1,23 @@
/*
* Copyright (c) 2021 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.api
import org.matrix.android.sdk.api.util.MatrixItem
interface MatrixItemDisplayNameFallbackProvider {
fun getDefaultName(matrixItem: MatrixItem): String
}

View File

@ -17,6 +17,8 @@
package org.matrix.android.sdk.api
import org.matrix.android.sdk.BuildConfig
import org.matrix.android.sdk.internal.util.removeInvalidRoomNameChars
import org.matrix.android.sdk.internal.util.replaceSpaceChars
import timber.log.Timber
/**
@ -128,10 +130,10 @@ object MatrixPatterns {
* @return true if the string is a valid event id.
*/
fun isEventId(str: String?): Boolean {
return str != null
&& (str matches PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER
|| str matches PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER_V3
|| str matches PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER_V4)
return str != null &&
(str matches PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER ||
str matches PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER_V3 ||
str matches PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER_V4)
}
/**
@ -162,10 +164,11 @@ object MatrixPatterns {
return order != null && order.length < 50 && order matches ORDER_STRING_REGEX
}
fun candidateAliasFromRoomName(name: String): String {
return Regex("\\s").replace(name.lowercase(), "_").let {
"[^a-z0-9._%#@=+-]".toRegex().replace(it, "")
}
fun candidateAliasFromRoomName(roomName: String, domain: String): String {
return roomName.lowercase()
.replaceSpaceChars(replacement = "_")
.removeInvalidRoomNameChars()
.take(MatrixConstants.maxAliasLocalPartLength(domain))
}
/**

View File

@ -0,0 +1,26 @@
/*
* 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
/**
* This class contains pattern to match Matrix Url, aka mxc urls
*/
object MatrixUrls {
const val MATRIX_CONTENT_URI_SCHEME = "mxc://"
fun String.isMxcUrl() = startsWith(MATRIX_CONTENT_URI_SCHEME)
}

View File

@ -23,20 +23,20 @@ import java.io.IOException
import javax.net.ssl.HttpsURLConnection
fun Throwable.is401() =
this is Failure.ServerError
&& httpCode == HttpsURLConnection.HTTP_UNAUTHORIZED /* 401 */
&& error.code == MatrixError.M_UNAUTHORIZED
this is Failure.ServerError &&
httpCode == HttpsURLConnection.HTTP_UNAUTHORIZED && /* 401 */
error.code == MatrixError.M_UNAUTHORIZED
fun Throwable.isTokenError() =
this is Failure.ServerError
&& (error.code == MatrixError.M_UNKNOWN_TOKEN
|| error.code == MatrixError.M_MISSING_TOKEN
|| error.code == MatrixError.ORG_MATRIX_EXPIRED_ACCOUNT)
this is Failure.ServerError &&
(error.code == MatrixError.M_UNKNOWN_TOKEN ||
error.code == MatrixError.M_MISSING_TOKEN ||
error.code == MatrixError.ORG_MATRIX_EXPIRED_ACCOUNT)
fun Throwable.shouldBeRetried(): Boolean {
return this is Failure.NetworkConnection
|| this is IOException
|| (this is Failure.ServerError && error.code == MatrixError.M_LIMIT_EXCEEDED)
return this is Failure.NetworkConnection ||
this is IOException ||
(this is Failure.ServerError && error.code == MatrixError.M_LIMIT_EXCEEDED)
}
/**
@ -52,31 +52,31 @@ fun Throwable.getRetryDelay(defaultValue: Long): Long {
}
fun Throwable.isInvalidPassword(): Boolean {
return this is Failure.ServerError
&& error.code == MatrixError.M_FORBIDDEN
&& error.message == "Invalid password"
return this is Failure.ServerError &&
error.code == MatrixError.M_FORBIDDEN &&
error.message == "Invalid password"
}
fun Throwable.isInvalidUIAAuth(): Boolean {
return this is Failure.ServerError
&& error.code == MatrixError.M_FORBIDDEN
&& error.flows != null
return this is Failure.ServerError &&
error.code == MatrixError.M_FORBIDDEN &&
error.flows != null
}
/**
* Try to convert to a RegistrationFlowResponse. Return null in the cases it's not possible
*/
fun Throwable.toRegistrationFlowResponse(): RegistrationFlowResponse? {
return if (this is Failure.OtherServerError
&& httpCode == HttpsURLConnection.HTTP_UNAUTHORIZED /* 401 */) {
return if (this is Failure.OtherServerError &&
httpCode == HttpsURLConnection.HTTP_UNAUTHORIZED /* 401 */) {
tryOrNull {
MoshiProvider.providesMoshi()
.adapter(RegistrationFlowResponse::class.java)
.fromJson(errorBody)
}
} else if (this is Failure.ServerError
&& httpCode == HttpsURLConnection.HTTP_UNAUTHORIZED /* 401 */
&& error.code == MatrixError.M_FORBIDDEN) {
} else if (this is Failure.ServerError &&
httpCode == HttpsURLConnection.HTTP_UNAUTHORIZED && /* 401 */
error.code == MatrixError.M_FORBIDDEN) {
// This happens when the submission for this stage was bad (like bad password)
if (error.session != null && error.flows != null) {
RegistrationFlowResponse(
@ -94,9 +94,9 @@ fun Throwable.toRegistrationFlowResponse(): RegistrationFlowResponse? {
}
fun Throwable.isRegistrationAvailabilityError(): Boolean {
return this is Failure.ServerError
&& httpCode == HttpsURLConnection.HTTP_BAD_REQUEST /* 400 */
&& (error.code == MatrixError.M_USER_IN_USE
|| error.code == MatrixError.M_INVALID_USERNAME
|| error.code == MatrixError.M_EXCLUSIVE)
return this is Failure.ServerError &&
httpCode == HttpsURLConnection.HTTP_BAD_REQUEST && /* 400 */
(error.code == MatrixError.M_USER_IN_USE ||
error.code == MatrixError.M_INVALID_USERNAME ||
error.code == MatrixError.M_EXCLUSIVE)
}

View File

@ -154,7 +154,6 @@ enum class ApiPath(val path: String, val method: String) {
SEND_STATE_EVENT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/state/{state_event_type}", "PUT"),
SEND_STATE_EVENT_WITH_STATE_KEY(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/state/{state_event_type}/{state_key}", "PUT"),
GET_ROOM_STATE(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/state", "GET"),
SEND_RELATION(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/send_relation/{parent_id}/{relation_type}/{event_type}", "POST"),
GET_RELATIONS(NetworkConstants.URI_API_PREFIX_PATH_UNSTABLE + "rooms/{roomId}/relations/{eventId}/{relationType}/{eventType}", "GET"),
JOIN_ROOM(NetworkConstants.URI_API_PREFIX_PATH_R0 + "join/{roomIdOrAlias}", "POST"),
LEAVE_ROOM(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/leave", "POST"),

View File

@ -18,6 +18,7 @@ package org.matrix.android.sdk.api.session
import androidx.annotation.MainThread
import androidx.lifecycle.LiveData
import kotlinx.coroutines.flow.SharedFlow
import okhttp3.OkHttpClient
import org.matrix.android.sdk.api.auth.data.SessionParams
import org.matrix.android.sdk.api.failure.GlobalError
@ -52,6 +53,7 @@ import org.matrix.android.sdk.api.session.signout.SignOutService
import org.matrix.android.sdk.api.session.space.SpaceService
import org.matrix.android.sdk.api.session.sync.FilterService
import org.matrix.android.sdk.api.session.sync.SyncState
import org.matrix.android.sdk.api.session.sync.model.SyncResponse
import org.matrix.android.sdk.api.session.terms.TermsService
import org.matrix.android.sdk.api.session.thirdparty.ThirdPartyService
import org.matrix.android.sdk.api.session.typing.TypingUsersTracker
@ -143,6 +145,11 @@ interface Session :
*/
fun getSyncState(): SyncState
/**
* This method returns a flow of SyncResponse. New value will be pushed through the sync thread.
*/
fun syncFlow(): SharedFlow<SyncResponse>
/**
* This methods return true if an initial sync has been processed
*/

View File

@ -24,8 +24,8 @@ data class MXCrossSigningInfo(
val crossSigningKeys: List<CryptoCrossSigningKey>
) {
fun isTrusted(): Boolean = masterKey()?.trustLevel?.isVerified() == true
&& selfSigningKey()?.trustLevel?.isVerified() == true
fun isTrusted(): Boolean = masterKey()?.trustLevel?.isVerified() == true &&
selfSigningKey()?.trustLevel?.isVerified() == true
fun masterKey(): CryptoCrossSigningKey? = crossSigningKeys
.firstOrNull { it.usages?.contains(KeyUsage.MASTER.value) == true }

View File

@ -16,8 +16,8 @@
package org.matrix.android.sdk.api.session.crypto.keyshare
import org.matrix.android.sdk.internal.crypto.IncomingRoomKeyRequest
import org.matrix.android.sdk.internal.crypto.IncomingRequestCancellation
import org.matrix.android.sdk.internal.crypto.IncomingRoomKeyRequest
import org.matrix.android.sdk.internal.crypto.IncomingSecretShareRequest
/**

View File

@ -48,8 +48,8 @@ data class PendingVerificationRequest(
* SAS is supported if I support it and the other party support it
*/
fun isSasSupported(): Boolean {
return requestInfo?.methods?.contains(VERIFICATION_METHOD_SAS).orFalse()
&& readyInfo?.methods?.contains(VERIFICATION_METHOD_SAS).orFalse()
return requestInfo?.methods?.contains(VERIFICATION_METHOD_SAS).orFalse() &&
readyInfo?.methods?.contains(VERIFICATION_METHOD_SAS).orFalse()
}
/**
@ -57,11 +57,11 @@ data class PendingVerificationRequest(
*/
fun otherCanShowQrCode(): Boolean {
return if (isIncoming) {
requestInfo?.methods?.contains(VERIFICATION_METHOD_QR_CODE_SHOW).orFalse()
&& readyInfo?.methods?.contains(VERIFICATION_METHOD_QR_CODE_SCAN).orFalse()
requestInfo?.methods?.contains(VERIFICATION_METHOD_QR_CODE_SHOW).orFalse() &&
readyInfo?.methods?.contains(VERIFICATION_METHOD_QR_CODE_SCAN).orFalse()
} else {
requestInfo?.methods?.contains(VERIFICATION_METHOD_QR_CODE_SCAN).orFalse()
&& readyInfo?.methods?.contains(VERIFICATION_METHOD_QR_CODE_SHOW).orFalse()
requestInfo?.methods?.contains(VERIFICATION_METHOD_QR_CODE_SCAN).orFalse() &&
readyInfo?.methods?.contains(VERIFICATION_METHOD_QR_CODE_SHOW).orFalse()
}
}
@ -70,11 +70,11 @@ data class PendingVerificationRequest(
*/
fun otherCanScanQrCode(): Boolean {
return if (isIncoming) {
requestInfo?.methods?.contains(VERIFICATION_METHOD_QR_CODE_SCAN).orFalse()
&& readyInfo?.methods?.contains(VERIFICATION_METHOD_QR_CODE_SHOW).orFalse()
requestInfo?.methods?.contains(VERIFICATION_METHOD_QR_CODE_SCAN).orFalse() &&
readyInfo?.methods?.contains(VERIFICATION_METHOD_QR_CODE_SHOW).orFalse()
} else {
requestInfo?.methods?.contains(VERIFICATION_METHOD_QR_CODE_SHOW).orFalse()
&& readyInfo?.methods?.contains(VERIFICATION_METHOD_QR_CODE_SCAN).orFalse()
requestInfo?.methods?.contains(VERIFICATION_METHOD_QR_CODE_SHOW).orFalse() &&
readyInfo?.methods?.contains(VERIFICATION_METHOD_QR_CODE_SCAN).orFalse()
}
}
}

View File

@ -18,6 +18,9 @@ package org.matrix.android.sdk.api.session.events.model
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import org.json.JSONObject
import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.failure.MatrixError
import org.matrix.android.sdk.api.session.crypto.MXCryptoError
import org.matrix.android.sdk.api.session.room.model.message.MessageContent
import org.matrix.android.sdk.api.session.room.model.message.MessageType
@ -27,9 +30,6 @@ import org.matrix.android.sdk.api.util.JsonDict
import org.matrix.android.sdk.internal.crypto.algorithms.olm.OlmDecryptionResult
import org.matrix.android.sdk.internal.crypto.model.event.EncryptedEventContent
import org.matrix.android.sdk.internal.di.MoshiProvider
import org.json.JSONObject
import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.failure.MatrixError
import timber.log.Timber
typealias Content = JsonDict
@ -238,8 +238,8 @@ data class Event(
}
fun Event.isTextMessage(): Boolean {
return getClearType() == EventType.MESSAGE
&& when (getClearContent()?.get(MessageContent.MSG_TYPE_JSON_KEY)) {
return getClearType() == EventType.MESSAGE &&
when (getClearContent()?.get(MessageContent.MSG_TYPE_JSON_KEY)) {
MessageType.MSGTYPE_TEXT,
MessageType.MSGTYPE_EMOTE,
MessageType.MSGTYPE_NOTICE -> true
@ -248,40 +248,40 @@ fun Event.isTextMessage(): Boolean {
}
fun Event.isImageMessage(): Boolean {
return getClearType() == EventType.MESSAGE
&& when (getClearContent()?.get(MessageContent.MSG_TYPE_JSON_KEY)) {
return getClearType() == EventType.MESSAGE &&
when (getClearContent()?.get(MessageContent.MSG_TYPE_JSON_KEY)) {
MessageType.MSGTYPE_IMAGE -> true
else -> false
}
}
fun Event.isVideoMessage(): Boolean {
return getClearType() == EventType.MESSAGE
&& when (getClearContent()?.get(MessageContent.MSG_TYPE_JSON_KEY)) {
return getClearType() == EventType.MESSAGE &&
when (getClearContent()?.get(MessageContent.MSG_TYPE_JSON_KEY)) {
MessageType.MSGTYPE_VIDEO -> true
else -> false
}
}
fun Event.isAudioMessage(): Boolean {
return getClearType() == EventType.MESSAGE
&& when (getClearContent()?.get(MessageContent.MSG_TYPE_JSON_KEY)) {
return getClearType() == EventType.MESSAGE &&
when (getClearContent()?.get(MessageContent.MSG_TYPE_JSON_KEY)) {
MessageType.MSGTYPE_AUDIO -> true
else -> false
}
}
fun Event.isFileMessage(): Boolean {
return getClearType() == EventType.MESSAGE
&& when (getClearContent()?.get(MessageContent.MSG_TYPE_JSON_KEY)) {
return getClearType() == EventType.MESSAGE &&
when (getClearContent()?.get(MessageContent.MSG_TYPE_JSON_KEY)) {
MessageType.MSGTYPE_FILE -> true
else -> false
}
}
fun Event.isAttachmentMessage(): Boolean {
return getClearType() == EventType.MESSAGE
&& when (getClearContent()?.get(MessageContent.MSG_TYPE_JSON_KEY)) {
return getClearType() == EventType.MESSAGE &&
when (getClearContent()?.get(MessageContent.MSG_TYPE_JSON_KEY)) {
MessageType.MSGTYPE_IMAGE,
MessageType.MSGTYPE_AUDIO,
MessageType.MSGTYPE_VIDEO,

View File

@ -106,13 +106,13 @@ object EventType {
internal const val DUMMY = "m.dummy"
fun isCallEvent(type: String): Boolean {
return type == CALL_INVITE
|| type == CALL_CANDIDATES
|| type == CALL_ANSWER
|| type == CALL_HANGUP
|| type == CALL_SELECT_ANSWER
|| type == CALL_NEGOTIATE
|| type == CALL_REJECT
|| type == CALL_REPLACES
return type == CALL_INVITE ||
type == CALL_CANDIDATES ||
type == CALL_ANSWER ||
type == CALL_HANGUP ||
type == CALL_SELECT_ANSWER ||
type == CALL_NEGOTIATE ||
type == CALL_REJECT ||
type == CALL_REPLACES
}
}

View File

@ -50,11 +50,11 @@ object MatrixLinkify {
if (startPos == 0 || text[startPos - 1] != '/') {
val endPos = match.range.last + 1
var url = text.substring(match.range)
if (MatrixPatterns.isUserId(url)
|| MatrixPatterns.isRoomAlias(url)
|| MatrixPatterns.isRoomId(url)
|| MatrixPatterns.isGroupId(url)
|| MatrixPatterns.isEventId(url)) {
if (MatrixPatterns.isUserId(url) ||
MatrixPatterns.isRoomAlias(url) ||
MatrixPatterns.isRoomId(url) ||
MatrixPatterns.isGroupId(url) ||
MatrixPatterns.isEventId(url)) {
url = PermalinkService.MATRIX_TO_URL_BASE + url
}
val span = MatrixPermalinkSpan(url, callback)

View File

@ -0,0 +1,55 @@
/*
* Copyright 2020 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.api.session.permalinks
import android.net.Uri
/**
* Mapping of an input URI to a matrix.to compliant URI.
*/
object MatrixToConverter {
/**
* Try to convert a URL from an element web instance or from a client permalink to a matrix.to url.
* To be successfully converted, URL path should contain one of the [SUPPORTED_PATHS].
* Examples:
* - https://riot.im/develop/#/room/#element-android:matrix.org -> https://matrix.to/#/#element-android:matrix.org
* - https://app.element.io/#/room/#element-android:matrix.org -> https://matrix.to/#/#element-android:matrix.org
* - https://www.example.org/#/room/#element-android:matrix.org -> https://matrix.to/#/#element-android:matrix.org
*/
fun convert(uri: Uri): Uri? {
val uriString = uri.toString()
return when {
// URL is already a matrix.to
uriString.startsWith(PermalinkService.MATRIX_TO_URL_BASE) -> uri
// Web or client url
SUPPORTED_PATHS.any { it in uriString } -> {
val path = SUPPORTED_PATHS.first { it in uriString }
Uri.parse(PermalinkService.MATRIX_TO_URL_BASE + uriString.substringAfter(path))
}
// URL is not supported
else -> null
}
}
private val SUPPORTED_PATHS = listOf(
"/#/room/",
"/#/user/",
"/#/group/"
)
}

View File

@ -26,6 +26,7 @@ import java.net.URLDecoder
* This class turns a uri to a [PermalinkData]
* element-based domains (e.g. https://app.element.io/#/user/@chagai95:matrix.org) permalinks
* or matrix.to permalinks (e.g. https://matrix.to/#/@chagai95:matrix.org)
* or client permalinks (e.g. <clientPermalinkBaseUrl>user/@chagai95:matrix.org)
*/
object PermalinkParser {
@ -42,13 +43,15 @@ object PermalinkParser {
* https://github.com/matrix-org/matrix-doc/blob/master/proposals/1704-matrix.to-permalinks.md
*/
fun parse(uri: Uri): PermalinkData {
if (!uri.toString().startsWith(PermalinkService.MATRIX_TO_URL_BASE)) {
return PermalinkData.FallbackLink(uri)
}
// the client or element-based domain permalinks (e.g. https://app.element.io/#/user/@chagai95:matrix.org) don't have the
// mxid in the first param (like matrix.to does - https://matrix.to/#/@chagai95:matrix.org) but rather in the second after /user/ so /user/mxid
// so convert URI to matrix.to to simplify parsing process
val matrixToUri = MatrixToConverter.convert(uri) ?: return PermalinkData.FallbackLink(uri)
// We can't use uri.fragment as it is decoding to early and it will break the parsing
// of parameters that represents url (like signurl)
val fragment = uri.toString().substringAfter("#") // uri.fragment
if (fragment.isNullOrEmpty()) {
val fragment = matrixToUri.toString().substringAfter("#") // uri.fragment
if (fragment.isEmpty()) {
return PermalinkData.FallbackLink(uri)
}
val safeFragment = fragment.substringBefore('?')
@ -61,20 +64,14 @@ object PermalinkParser {
.map { URLDecoder.decode(it, "UTF-8") }
.take(2)
// the element-based domain permalinks (e.g. https://app.element.io/#/user/@chagai95:matrix.org) don't have the
// mxid in the first param (like matrix.to does - https://matrix.to/#/@chagai95:matrix.org) but rather in the second after /user/ so /user/mxid
var identifier = params.getOrNull(0)
if (identifier.equals("user")) {
identifier = params.getOrNull(1)
}
val identifier = params.getOrNull(0)
val extraParameter = params.getOrNull(1)
return when {
identifier.isNullOrEmpty() -> PermalinkData.FallbackLink(uri)
MatrixPatterns.isUserId(identifier) -> PermalinkData.UserLink(userId = identifier)
MatrixPatterns.isGroupId(identifier) -> PermalinkData.GroupLink(groupId = identifier)
MatrixPatterns.isRoomId(identifier) -> {
handleRoomIdCase(fragment, identifier, uri, extraParameter, viaQueryParameters)
handleRoomIdCase(fragment, identifier, matrixToUri, extraParameter, viaQueryParameters)
}
MatrixPatterns.isRoomAlias(identifier) -> {
PermalinkData.RoomLink(
@ -125,7 +122,8 @@ object PermalinkParser {
}
}
private fun safeExtractParams(fragment: String) = fragment.substringAfter("?").split('&').mapNotNull {
private fun safeExtractParams(fragment: String) =
fragment.substringAfter("?").split('&').mapNotNull {
val splitNameValue = it.split("=")
if (splitNameValue.size == 2) {
Pair(splitNameValue[0], URLDecoder.decode(splitNameValue[1], "UTF-8"))
@ -138,9 +136,7 @@ object PermalinkParser {
.filter {
it.mParameter == "via"
}.map {
it.mValue.let {
URLDecoder.decode(it, "UTF-8")
}
URLDecoder.decode(it.mValue, "UTF-8")
}
}
}

View File

@ -19,7 +19,8 @@ package org.matrix.android.sdk.api.session.permalinks
import org.matrix.android.sdk.api.session.events.model.Event
/**
* Useful methods to create Matrix permalink (matrix.to links).
* Useful methods to create permalink (like matrix.to links or client permalinks).
* See [org.matrix.android.sdk.api.MatrixConfiguration.clientPermalinkBaseUrl] to setup a custom permalink base url.
*/
interface PermalinkService {
@ -32,10 +33,11 @@ interface PermalinkService {
* Ex: "https://matrix.to/#/!nbzmcXAqpxBXjAdgoX:matrix.org/$1531497316352799BevdV:matrix.org"
*
* @param event the event
* @param forceMatrixTo whether we should force using matrix.to base URL
*
* @return the permalink, or null in case of error
*/
fun createPermalink(event: Event): String?
fun createPermalink(event: Event, forceMatrixTo: Boolean = false): String?
/**
* Creates a permalink for an id (can be a user Id, etc.).
@ -43,18 +45,21 @@ interface PermalinkService {
* Ex: "https://matrix.to/#/@benoit:matrix.org"
*
* @param id the id
* @param forceMatrixTo whether we should force using matrix.to base URL
*
* @return the permalink, or null in case of error
*/
fun createPermalink(id: String): String?
fun createPermalink(id: String, forceMatrixTo: Boolean = false): String?
/**
* Creates a permalink for a roomId, including the via parameters
*
* @param roomId the room id
* @param forceMatrixTo whether we should force using matrix.to base URL
*
* @return the permalink, or null in case of error
*/
fun createRoomPermalink(roomId: String, viaServers: List<String>? = null): String?
fun createRoomPermalink(roomId: String, viaServers: List<String>? = null, forceMatrixTo: Boolean = false): String?
/**
* Creates a permalink for an event. If you have an event you can use [createPermalink]
@ -62,10 +67,11 @@ interface PermalinkService {
*
* @param roomId the id of the room
* @param eventId the id of the event
* @param forceMatrixTo whether we should force using matrix.to base URL
*
* @return the permalink
*/
fun createPermalink(roomId: String, eventId: String): String
fun createPermalink(roomId: String, eventId: String, forceMatrixTo: Boolean = false): String
/**
* Extract the linked id from the universal link

View File

@ -22,8 +22,8 @@ sealed class SharedSecretStorageError(message: String?) : Throwable(message) {
data class UnknownAlgorithm(val keyId: String) : SharedSecretStorageError("Unknown algorithm $keyId")
data class UnsupportedAlgorithm(val algorithm: String) : SharedSecretStorageError("Unknown algorithm $algorithm")
data class SecretNotEncrypted(val secretName: String) : SharedSecretStorageError("Missing content for secret $secretName")
data class SecretNotEncryptedWithKey(val secretName: String, val keyId: String)
: SharedSecretStorageError("Missing content for secret $secretName with key $keyId")
data class SecretNotEncryptedWithKey(val secretName: String, val keyId: String) :
SharedSecretStorageError("Missing content for secret $secretName with key $keyId")
object BadKeyFormat : SharedSecretStorageError("Bad Key Format")
object ParsingError : SharedSecretStorageError("parsing Error")

View File

@ -13,7 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.session.sync.model
package org.matrix.android.sdk.api.session.sync.model
import com.squareup.moshi.JsonClass
@ -21,7 +22,7 @@ import com.squareup.moshi.JsonClass
* This class describes the device list response from a sync request
*/
@JsonClass(generateAdapter = true)
internal data class DeviceListResponse(
data class DeviceListResponse(
// user ids list which have new crypto devices
val changed: List<String> = emptyList(),
// List of user ids who are no more tracked.

View File

@ -14,12 +14,12 @@
* limitations under the License.
*/
package org.matrix.android.sdk.internal.session.sync.model
package org.matrix.android.sdk.api.session.sync.model
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
internal data class DeviceOneTimeKeysCountSyncResponse(
data class DeviceOneTimeKeysCountSyncResponse(
@Json(name = "signed_curve25519") val signedCurve25519: Int? = null
)

View File

@ -14,13 +14,13 @@
* limitations under the License.
*/
package org.matrix.android.sdk.internal.session.sync.model
package org.matrix.android.sdk.api.session.sync.model
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
internal data class GroupSyncProfile(
data class GroupSyncProfile(
/**
* The name of the group, if any. May be nil.
*/

View File

@ -14,13 +14,13 @@
* limitations under the License.
*/
package org.matrix.android.sdk.internal.session.sync.model
package org.matrix.android.sdk.api.session.sync.model
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
internal data class GroupsSyncResponse(
data class GroupsSyncResponse(
/**
* Joined groups: An array of groups ids.
*/

View File

@ -14,13 +14,13 @@
* limitations under the License.
*/
package org.matrix.android.sdk.internal.session.sync.model
package org.matrix.android.sdk.api.session.sync.model
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
internal data class InvitedGroupSync(
data class InvitedGroupSync(
/**
* The identifier of the inviter.
*/

View File

@ -13,14 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.session.sync.model
package org.matrix.android.sdk.api.session.sync.model
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
// InvitedRoomSync represents a room invitation during server sync v2.
@JsonClass(generateAdapter = true)
internal data class InvitedRoomSync(
data class InvitedRoomSync(
/**
* The state of a room that the user has been invited to. These state events may only have the 'sender', 'type', 'state_key'

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021 The Matrix.org Foundation C.I.C.
* Copyright 2020 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -14,12 +14,12 @@
* limitations under the License.
*/
package org.matrix.android.sdk.internal.session.sync.model
package org.matrix.android.sdk.api.session.sync.model
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = false)
internal sealed class LazyRoomSyncEphemeral {
sealed class LazyRoomSyncEphemeral {
data class Parsed(val _roomSyncEphemeral: RoomSyncEphemeral) : LazyRoomSyncEphemeral()
object Stored : LazyRoomSyncEphemeral()
}

View File

@ -14,14 +14,14 @@
* limitations under the License.
*/
package org.matrix.android.sdk.internal.session.sync.model
package org.matrix.android.sdk.api.session.sync.model
import com.squareup.moshi.JsonClass
import org.matrix.android.sdk.api.session.events.model.Event
// PresenceSyncResponse represents the updates to the presence status of other users during server sync v2.
@JsonClass(generateAdapter = true)
internal data class PresenceSyncResponse(
data class PresenceSyncResponse(
/**
* List of presence events (array of Event with type m.presence).

View File

@ -13,7 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.session.sync.model
package org.matrix.android.sdk.api.session.sync.model
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@ -21,7 +22,7 @@ import org.matrix.android.sdk.api.session.events.model.Event
// RoomInviteState represents the state of a room that the user has been invited to.
@JsonClass(generateAdapter = true)
internal data class RoomInviteState(
data class RoomInviteState(
/**
* List of state events (array of MXEvent).

View File

@ -13,14 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.session.sync.model
package org.matrix.android.sdk.api.session.sync.model
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
// RoomSync represents the response for a room during server sync v2.
@JsonClass(generateAdapter = true)
internal data class RoomSync(
data class RoomSync(
/**
* The state updates for the room.
*/

View File

@ -14,14 +14,14 @@
* limitations under the License.
*/
package org.matrix.android.sdk.internal.session.sync.model
package org.matrix.android.sdk.api.session.sync.model
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import org.matrix.android.sdk.api.session.events.model.Event
@JsonClass(generateAdapter = true)
internal data class RoomSyncAccountData(
data class RoomSyncAccountData(
/**
* List of account data events (array of Event).
*/

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.matrix.android.sdk.internal.session.sync.model
package org.matrix.android.sdk.api.session.sync.model
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@ -22,7 +22,7 @@ import org.matrix.android.sdk.api.session.events.model.Event
// RoomSyncEphemeral represents the ephemeral events in the room that aren't recorded in the timeline or state of the room (e.g. typing).
@JsonClass(generateAdapter = true)
internal data class RoomSyncEphemeral(
data class RoomSyncEphemeral(
/**
* List of ephemeral events (array of Event).
*/

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.matrix.android.sdk.internal.session.sync.model
package org.matrix.android.sdk.api.session.sync.model
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@ -22,7 +22,7 @@ import org.matrix.android.sdk.api.session.events.model.Event
// RoomSyncState represents the state updates for a room during server sync v2.
@JsonClass(generateAdapter = true)
internal data class RoomSyncState(
data class RoomSyncState(
/**
* List of state events (array of Event). The resulting state corresponds to the *start* of the timeline.

View File

@ -14,13 +14,13 @@
* limitations under the License.
*/
package org.matrix.android.sdk.internal.session.sync.model
package org.matrix.android.sdk.api.session.sync.model
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
internal data class RoomSyncSummary(
data class RoomSyncSummary(
/**
* Present only if the room has no m.room.name or m.room.canonical_alias.

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.matrix.android.sdk.internal.session.sync.model
package org.matrix.android.sdk.api.session.sync.model
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@ -22,7 +22,7 @@ import org.matrix.android.sdk.api.session.events.model.Event
// RoomSyncTimeline represents the timeline of messages and state changes for a room during server sync v2.
@JsonClass(generateAdapter = true)
internal data class RoomSyncTimeline(
data class RoomSyncTimeline(
/**
* List of events (array of Event).

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.matrix.android.sdk.internal.session.sync.model
package org.matrix.android.sdk.api.session.sync.model
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@ -24,7 +24,7 @@ import org.matrix.android.sdk.api.session.events.model.Event
* `MXRoomSyncUnreadNotifications` represents the unread counts for a room.
*/
@JsonClass(generateAdapter = true)
internal data class RoomSyncUnreadNotifications(
data class RoomSyncUnreadNotifications(
/**
* List of account data events (array of Event).
*/

View File

@ -13,14 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.session.sync.model
package org.matrix.android.sdk.api.session.sync.model
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
// RoomsSyncResponse represents the rooms list in server sync v2 response.
@JsonClass(generateAdapter = true)
internal data class RoomsSyncResponse(
data class RoomsSyncResponse(
/**
* Joined rooms: keys are rooms ids.
*/

View File

@ -14,15 +14,14 @@
* limitations under the License.
*/
package org.matrix.android.sdk.internal.session.sync.model
package org.matrix.android.sdk.api.session.sync.model
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import org.matrix.android.sdk.internal.session.sync.model.accountdata.UserAccountDataSync
// SyncResponse represents the request response for server sync v2.
@JsonClass(generateAdapter = true)
internal data class SyncResponse(
data class SyncResponse(
/**
* The user private data.
*/

View File

@ -14,14 +14,14 @@
* limitations under the License.
*/
package org.matrix.android.sdk.internal.session.sync.model
package org.matrix.android.sdk.api.session.sync.model
import com.squareup.moshi.JsonClass
import org.matrix.android.sdk.api.session.events.model.Event
// ToDeviceSyncResponse represents the data directly sent to one of user's devices.
@JsonClass(generateAdapter = true)
internal data class ToDeviceSyncResponse(
data class ToDeviceSyncResponse(
/**
* List of direct-to-device events.

View File

@ -14,13 +14,13 @@
* limitations under the License.
*/
package org.matrix.android.sdk.internal.session.sync.model.accountdata
package org.matrix.android.sdk.api.session.sync.model
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import org.matrix.android.sdk.api.session.accountdata.UserAccountDataEvent
@JsonClass(generateAdapter = true)
internal data class UserAccountDataSync(
data class UserAccountDataSync(
@Json(name = "events") val list: List<UserAccountDataEvent> = emptyList()
)

View File

@ -23,13 +23,8 @@ package org.matrix.android.sdk.api.session.user.model
data class User(
val userId: String,
/**
* For usage in UI, consider using [getBestName]
* For usage in UI, consider converting to MatrixItem and call getBestName()
*/
val displayName: String? = null,
val avatarUrl: String? = null
) {
/**
* Return the display name or the user id
*/
fun getBestName() = displayName?.takeIf { it.isNotEmpty() } ?: userId
}
)

View File

@ -34,8 +34,8 @@ sealed class MatrixItem(
) {
data class UserItem(override val id: String,
override val displayName: String? = null,
override val avatarUrl: String? = null)
: MatrixItem(id, displayName?.removeSuffix(ircPattern), avatarUrl) {
override val avatarUrl: String? = null) :
MatrixItem(id, displayName?.removeSuffix(ircPattern), avatarUrl) {
init {
if (BuildConfig.DEBUG) checkId()
}
@ -45,8 +45,8 @@ sealed class MatrixItem(
data class EventItem(override val id: String,
override val displayName: String? = null,
override val avatarUrl: String? = null)
: MatrixItem(id, displayName, avatarUrl) {
override val avatarUrl: String? = null) :
MatrixItem(id, displayName, avatarUrl) {
init {
if (BuildConfig.DEBUG) checkId()
}
@ -56,8 +56,8 @@ sealed class MatrixItem(
data class RoomItem(override val id: String,
override val displayName: String? = null,
override val avatarUrl: String? = null)
: MatrixItem(id, displayName, avatarUrl) {
override val avatarUrl: String? = null) :
MatrixItem(id, displayName, avatarUrl) {
init {
if (BuildConfig.DEBUG) checkId()
}
@ -67,8 +67,8 @@ sealed class MatrixItem(
data class SpaceItem(override val id: String,
override val displayName: String? = null,
override val avatarUrl: String? = null)
: MatrixItem(id, displayName, avatarUrl) {
override val avatarUrl: String? = null) :
MatrixItem(id, displayName, avatarUrl) {
init {
if (BuildConfig.DEBUG) checkId()
}
@ -78,36 +78,26 @@ sealed class MatrixItem(
data class RoomAliasItem(override val id: String,
override val displayName: String? = null,
override val avatarUrl: String? = null)
: MatrixItem(id, displayName, avatarUrl) {
override val avatarUrl: String? = null) :
MatrixItem(id, displayName, avatarUrl) {
init {
if (BuildConfig.DEBUG) checkId()
}
// Best name is the id, and we keep the displayName of the room for the case we need the first letter
override fun getBestName() = id
override fun updateAvatar(newAvatar: String?) = copy(avatarUrl = newAvatar)
}
data class GroupItem(override val id: String,
override val displayName: String? = null,
override val avatarUrl: String? = null)
: MatrixItem(id, displayName, avatarUrl) {
override val avatarUrl: String? = null) :
MatrixItem(id, displayName, avatarUrl) {
init {
if (BuildConfig.DEBUG) checkId()
}
// Best name is the id, and we keep the displayName of the room for the case we need the first letter
override fun getBestName() = id
override fun updateAvatar(newAvatar: String?) = copy(avatarUrl = newAvatar)
}
open fun getBestName(): String {
return displayName?.takeIf { it.isNotBlank() } ?: id
}
protected fun checkId() {
if (!id.startsWith(getIdPrefix())) {
error("Wrong usage of MatrixItem: check the id $id should start with ${getIdPrefix()}")

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