Merge branch 'develop' into feature/bca/devtools
This commit is contained in:
commit
cf0b4d2581
26
CHANGES.md
26
CHANGES.md
@ -1,20 +1,23 @@
|
||||
Changes in Element 1.0.18 (2020-XX-XX)
|
||||
Changes in Element 1.0.18 (2021-XX-XX)
|
||||
===================================================
|
||||
|
||||
Features ✨:
|
||||
-
|
||||
|
||||
- VoIP : support for VoIP V1 protocol, transfer call and dial-pad
|
||||
|
||||
Improvements 🙌:
|
||||
-
|
||||
- VoIP : new tiles in timeline
|
||||
- Improve room profile UX
|
||||
- Upgrade Jitsi library from 2.9.3 to 3.1.0
|
||||
|
||||
Bugfix 🐛:
|
||||
-
|
||||
- VoIP : fix audio devices output
|
||||
- Fix crash after initial sync on Dendrite
|
||||
|
||||
Translations 🗣:
|
||||
-
|
||||
|
||||
SDK API changes ⚠️:
|
||||
-
|
||||
-
|
||||
|
||||
Build 🧱:
|
||||
-
|
||||
@ -24,8 +27,9 @@ Test:
|
||||
|
||||
Other changes:
|
||||
- New Dev Tools panel for developers
|
||||
- Fix typos in CHANGES.md (#2811)
|
||||
|
||||
Changes in Element 1.0.17 (2020-02-09)
|
||||
Changes in Element 1.0.17 (2021-02-09)
|
||||
===================================================
|
||||
|
||||
Improvements 🙌:
|
||||
@ -47,13 +51,13 @@ Build 🧱:
|
||||
Other changes:
|
||||
- Change app name from "Element (Riot.im)" to "Element"
|
||||
|
||||
Changes in Element 1.0.16 (2020-02-04)
|
||||
Changes in Element 1.0.16 (2021-02-04)
|
||||
===================================================
|
||||
|
||||
Bugfix 🐛:
|
||||
- Fix crash on API < 30 and light theme (#2774)
|
||||
|
||||
Changes in Element 1.0.15 (2020-02-03)
|
||||
Changes in Element 1.0.15 (2021-02-03)
|
||||
===================================================
|
||||
|
||||
Features ✨:
|
||||
@ -84,7 +88,7 @@ Build 🧱:
|
||||
Other changes:
|
||||
- Update Dagger to 2.31 version so we can use the embedded AssistedInject feature
|
||||
|
||||
Changes in Element 1.0.14 (2020-01-15)
|
||||
Changes in Element 1.0.14 (2021-01-15)
|
||||
===================================================
|
||||
|
||||
Features ✨:
|
||||
@ -1196,7 +1200,7 @@ Mode details here: https://medium.com/@RiotChat/introducing-the-riotx-beta-for-a
|
||||
=======================================================
|
||||
|
||||
|
||||
Changes in Element 1.X.X (2020-XX-XX)
|
||||
Changes in Element 1.X.X (2021-XX-XX)
|
||||
===================================================
|
||||
|
||||
Features ✨:
|
||||
|
@ -58,9 +58,9 @@ allprojects {
|
||||
maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
|
||||
// Jitsi repo
|
||||
maven {
|
||||
url "https://github.com/vector-im/jitsi_libre_maven/raw/master/android-sdk-2.9.3"
|
||||
url "https://github.com/vector-im/jitsi_libre_maven/raw/master/android-sdk-3.1.0"
|
||||
// Note: to test Jitsi release you can use a local file like this:
|
||||
// url "file:///Users/bmarty/workspaces/jitsi_libre_maven/android-sdk-2.9.3"
|
||||
// url "file:///Users/bmarty/workspaces/jitsi_libre_maven/android-sdk-3.1.0"
|
||||
}
|
||||
google()
|
||||
jcenter()
|
||||
|
@ -18,7 +18,7 @@ The generated maven repository is then host in the project https://github.com/ve
|
||||
|
||||
Update the script `./tools/jitsi/build_jisti_libs.sh` with the tag of the project `https://github.com/jitsi/jitsi-meet`.
|
||||
|
||||
Currently we are building the version with the tag `android-sdk-2.9.3`.
|
||||
Currently we are building the version with the tag `android-sdk-3.1.0`.
|
||||
|
||||
### Run the build script
|
||||
|
||||
@ -35,21 +35,21 @@ It will build the Jitsi Meet Android library and put every generated files in th
|
||||
- Update the file `./build.gradle` to use the previously created local Maven repository. Currently we have this line:
|
||||
|
||||
```groovy
|
||||
url "https://github.com/vector-im/jitsi_libre_maven/raw/master/android-sdk-2.9.3"
|
||||
url "https://github.com/vector-im/jitsi_libre_maven/raw/master/android-sdk-3.1.0"
|
||||
```
|
||||
|
||||
You can uncomment and update the line starting with `// url "file://...` and comment the line starting with `url`, to test the library using the locally generated Maven repository.
|
||||
|
||||
- Update the dependency of the WebRTC library in the file `./matrix-sdk-android/build.gradle`. Currently we have this line:
|
||||
|
||||
```groovy
|
||||
implementation('com.facebook.react:react-native-webrtc:1.84.0-jitsi-5112273@aar')
|
||||
```
|
||||
|
||||
- Update the dependency of the Jitsi Meet library in the file `./vector/build.gradle`. Currently we have this line:
|
||||
|
||||
```groovy
|
||||
implementation('org.jitsi.react:jitsi-meet-sdk:2.9.3') { transitive = true }
|
||||
implementation('org.jitsi.react:jitsi-meet-sdk:3.1.0')
|
||||
```
|
||||
|
||||
- Update the dependency of the WebRTC library in the file `./vector/build.gradle`. Currently we have this line:
|
||||
|
||||
```groovy
|
||||
implementation('com.facebook.react:react-native-webrtc:1.87.3-jitsi-6624067@aar')
|
||||
```
|
||||
|
||||
- Perform a gradle sync and build the project
|
||||
@ -74,9 +74,9 @@ If all the tests are passed, you can export the generated Jitsi library to our M
|
||||
- Update the file `./build.gradle` to use the previously created Maven repository. Currently we have this line:
|
||||
|
||||
```groovy
|
||||
url "https://github.com/vector-im/jitsi_libre_maven/raw/master/android-sdk-2.9.3"
|
||||
url "https://github.com/vector-im/jitsi_libre_maven/raw/master/android-sdk-3.1.0"
|
||||
```
|
||||
|
||||
- Build the project and perform the sanity tests again.
|
||||
|
||||
- Update the file `/CANGES.md` to notify about the library upgrade, and create a regular PR for project Element Android.
|
||||
- Update the file `/CHANGES.md` to notify about the library upgrade, and create a regular PR for project Element Android.
|
@ -1,2 +1,2 @@
|
||||
Canvis principals d'aquesta versió: previsualització d'URL, nou teclat d'emoticones, noves funcions de configuració de les sales i neu pel Nadal!
|
||||
Registre de canvis complet: https://github.com/vector-im/element-android/releases/tag/v1.0.12
|
||||
Registre de canvis complet: https://github.com/vector-im/element-android/releases/tag/v1.0.13
|
||||
|
2
fastlane/metadata/android/ca/changelogs/40100140.txt
Normal file
2
fastlane/metadata/android/ca/changelogs/40100140.txt
Normal file
@ -0,0 +1,2 @@
|
||||
Canvis principals d'aquesta versió: modificació dels permisos de sala, tema clar/fosc automàtic, correcció d'errors.
|
||||
Registre de canvis complet: https://github.com/vector-im/element-android/releases/tag/v1.0.14
|
2
fastlane/metadata/android/ca/changelogs/40100150.txt
Normal file
2
fastlane/metadata/android/ca/changelogs/40100150.txt
Normal file
@ -0,0 +1,2 @@
|
||||
Canvis principals d'aquesta versió: inici de sessió amb xarxes socials.
|
||||
Registre de canvis complet: https://github.com/vector-im/element-android/releases/tag/v1.0.15
|
2
fastlane/metadata/android/ca/changelogs/40100160.txt
Normal file
2
fastlane/metadata/android/ca/changelogs/40100160.txt
Normal file
@ -0,0 +1,2 @@
|
||||
Canvis principals d'aquesta versió: inici de sessió amb xarxes socials.
|
||||
Registre de canvis complet: https://github.com/vector-im/element-android/releases/tag/v1.0.15 i https://github.com/vector-im/element-android/releases/tag/v1.0.16
|
@ -1 +1 @@
|
||||
Xat i VoIP segurs i descentralitzats. Protegeix les teves dades de tercers.
|
||||
Xats i VoIP segurs i descentralitzats. Protegeix les teves dades de tercers.
|
||||
|
@ -1 +1 @@
|
||||
Element (anteriorment Riot.im)
|
||||
Element (abans Riot.im)
|
||||
|
@ -1,2 +1,2 @@
|
||||
Hauptänderungen in dieser Version: URL-Vorschau, neue Emoji-Tastatur, neue Raumeinstellungen und Schnee für Weihnachten!
|
||||
Vollständiges Änderungsprotokoll: https://github.com/vector-im/element-android/releases/tag/v1.0.12
|
||||
Vollständiges Änderungsprotokoll: https://github.com/vector-im/element-android/releases/tag/v1.0.13
|
||||
|
2
fastlane/metadata/android/de/changelogs/40100140.txt
Normal file
2
fastlane/metadata/android/de/changelogs/40100140.txt
Normal file
@ -0,0 +1,2 @@
|
||||
Hauptänderungen in dieser Version: Bearbeiten von Raumberechtigungen, automatisches Hell/Dunkel-Design und eine Reihe von Fehlerkorrekturen.
|
||||
Vollständiges Änderungsprotokoll: https://github.com/vector-im/element-android/releases/tag/v1.0.14
|
2
fastlane/metadata/android/de/changelogs/40100150.txt
Normal file
2
fastlane/metadata/android/de/changelogs/40100150.txt
Normal file
@ -0,0 +1,2 @@
|
||||
Hauptänderungen in dieser Version: Unterstützung für soziale Anmeldungen.
|
||||
Vollständiges Änderungsprotokoll: https://github.com/vector-im/element-android/releases/tag/v1.0.15
|
2
fastlane/metadata/android/de/changelogs/40100160.txt
Normal file
2
fastlane/metadata/android/de/changelogs/40100160.txt
Normal file
@ -0,0 +1,2 @@
|
||||
Hauptänderungen in dieser Version: Unterstützung für soziale Anmeldungen.
|
||||
Vollständiges Änderungsprotokoll: https://github.com/vector-im/element-android/releases/tag/v1.0.15 and https://github.com/vector-im/element-android/releases/tag/v1.0.16
|
@ -1,2 +1,2 @@
|
||||
Olulisemad muutused selles versioonis: URLide eelvaade, uus klahvistik emojide jaoks, jututubade uued seadistused ja natuke lund jõuludeks!
|
||||
Muudatuste logi täismahus: https://github.com/vector-im/element-android/releases/tag/v1.0.12
|
||||
Muudatuste logi täismahus: https://github.com/vector-im/element-android/releases/tag/v1.0.13
|
||||
|
2
fastlane/metadata/android/et/changelogs/40100140.txt
Normal file
2
fastlane/metadata/android/et/changelogs/40100140.txt
Normal file
@ -0,0 +1,2 @@
|
||||
Olulisemad muutused selles versioonis: Jututoa õiguste muutmine, automaatne tumeda ja heleda teema vahetamine ning märgatav kogus veaparandusi.
|
||||
Muudatuste logi täismahus: https://github.com/vector-im/element-android/releases/tag/v1.0.14
|
2
fastlane/metadata/android/et/changelogs/40100150.txt
Normal file
2
fastlane/metadata/android/et/changelogs/40100150.txt
Normal file
@ -0,0 +1,2 @@
|
||||
Olulisemad muutused selles versioonis: Sisselogimine sotsiaalmeediakontode abil.
|
||||
Muudatuste logi täismahus: https://github.com/vector-im/element-android/releases/tag/v1.0.15
|
2
fastlane/metadata/android/et/changelogs/40100160.txt
Normal file
2
fastlane/metadata/android/et/changelogs/40100160.txt
Normal file
@ -0,0 +1,2 @@
|
||||
Olulisemad muutused selles versioonis: Sisselogimine sotsiaalmeediakontode abil.
|
||||
Muudatuste logi täismahus: https://github.com/vector-im/element-android/releases/tag/v1.0.15 ja https://github.com/vector-im/element-android/releases/tag/v1.0.16
|
@ -1,2 +1,2 @@
|
||||
Principais mudanças nessa versão: Prévia do endereço URL, novo teclado de Emojis, novos recursos de configuração da sala, e neve para o Natal!
|
||||
Registro de alterações completo: https://github.com/vector-im/element-android/releases/tag/v1.0.12
|
||||
Registro de alterações completo: https://github.com/vector-im/element-android/releases/tag/v1.0.13
|
||||
|
2
fastlane/metadata/android/pt_BR/changelogs/40100140.txt
Normal file
2
fastlane/metadata/android/pt_BR/changelogs/40100140.txt
Normal file
@ -0,0 +1,2 @@
|
||||
Principais mudanças nessa versão: editar permissões da sala, tema automaticamente claro/escuro e várias correções de erros.
|
||||
Registro de alterações completo: https://github.com/vector-im/element-android/releases/tag/v1.0.14
|
2
fastlane/metadata/android/pt_BR/changelogs/40100150.txt
Normal file
2
fastlane/metadata/android/pt_BR/changelogs/40100150.txt
Normal file
@ -0,0 +1,2 @@
|
||||
Principais mudanças nessa versão: suporte para Login Social.
|
||||
Registro de alterações completo: https://github.com/vector-im/element-android/releases/tag/v1.0.15
|
2
fastlane/metadata/android/pt_BR/changelogs/40100160.txt
Normal file
2
fastlane/metadata/android/pt_BR/changelogs/40100160.txt
Normal file
@ -0,0 +1,2 @@
|
||||
Principais mudanças nessa versão: suporte para Login Social.
|
||||
Registro de alterações completo: https://github.com/vector-im/element-android/releases/tag/v1.0.15 e https://github.com/vector-im/element-android/releases/tag/v1.0.16
|
@ -1,2 +1,2 @@
|
||||
Основные изменения в этой версии: предварительный просмотр URL, новая клавиатура эмодзи, новые возможности настройки комнаты и снег на Рождество!
|
||||
Полный список изменений: https://github.com/vector-im/element-android/releases/tag/v1.0.12
|
||||
Полный список изменений: https://github.com/vector-im/element-android/releases/tag/v1.0.13
|
||||
|
2
fastlane/metadata/android/ru/changelogs/40100140.txt
Normal file
2
fastlane/metadata/android/ru/changelogs/40100140.txt
Normal file
@ -0,0 +1,2 @@
|
||||
Основные изменения в этой версии: Редактирование разрешений для комнаты, автоматическая светлая/темная тема и множество исправлений ошибок.
|
||||
Полный список изменений: https://github.com/vector-im/element-android/releases/tag/v1.0.14
|
2
fastlane/metadata/android/ru/changelogs/40100150.txt
Normal file
2
fastlane/metadata/android/ru/changelogs/40100150.txt
Normal file
@ -0,0 +1,2 @@
|
||||
Основные изменения в этой версии: Поддержка входа в социальные сети.
|
||||
Полный список изменений: https://github.com/vector-im/element-android/releases/tag/v1.0.15
|
2
fastlane/metadata/android/ru/changelogs/40100160.txt
Normal file
2
fastlane/metadata/android/ru/changelogs/40100160.txt
Normal file
@ -0,0 +1,2 @@
|
||||
Основные изменения в этой версии: Поддержка входа в социальные сети.
|
||||
Полный список изменений: https://github.com/vector-im/element-android/releases/tag/v1.0.15 and https://github.com/vector-im/element-android/releases/tag/v1.0.16
|
@ -1,2 +1,2 @@
|
||||
Главне измене у овој верзији: УРЛ преглед, нова емоџи тастатура, нове могућности у поставкама собе и снег за Божић !
|
||||
Дневник свих измена: https://github.com/vector-im/element-android/releases/tag/v1.0.12
|
||||
Главне измене у овој верзији: УРЛ преглед, нова емоџи тастатура, нове могућности у поставкама собе и снег за Божић!
|
||||
Дневник свих измена: https://github.com/vector-im/element-android/releases/tag/v1.0.13
|
||||
|
2
fastlane/metadata/android/sr/changelogs/40100140.txt
Normal file
2
fastlane/metadata/android/sr/changelogs/40100140.txt
Normal file
@ -0,0 +1,2 @@
|
||||
Главна измена у овој верзији: уређивање дозвола у соби, аутоматска светла/тамна тема и гомила исправљених грешака.
|
||||
Цео дневник измена: https://github.com/vector-im/element-android/releases/tag/v1.0.14
|
2
fastlane/metadata/android/sr/changelogs/40100150.txt
Normal file
2
fastlane/metadata/android/sr/changelogs/40100150.txt
Normal file
@ -0,0 +1,2 @@
|
||||
Главна измена у овој верзији: подршка за пријављивање са друштвених мрежа.
|
||||
Цео дневник измена: https://github.com/vector-im/element-android/releases/tag/v1.0.15
|
2
fastlane/metadata/android/sr/changelogs/40100160.txt
Normal file
2
fastlane/metadata/android/sr/changelogs/40100160.txt
Normal file
@ -0,0 +1,2 @@
|
||||
Главна измена у овој верзији: подршка за пријављивање са друштвених мрежа.
|
||||
Цео дневник измена: https://github.com/vector-im/element-android/releases/tag/v1.0.15 и https://github.com/vector-im/element-android/releases/tag/v1.0.16
|
@ -1,2 +1,2 @@
|
||||
Huvudsakliga ändringar i den här versionen: URL-förhandsgranskning, nya rumsinställningsförmågor, och en vit jul!
|
||||
Full ändringslogg: https://github.com/vector-im/element-android/releases/tag/v1.0.12
|
||||
Full ändringslogg: https://github.com/vector-im/element-android/releases/tag/v1.0.13
|
||||
|
2
fastlane/metadata/android/sv/changelogs/40100140.txt
Normal file
2
fastlane/metadata/android/sv/changelogs/40100140.txt
Normal file
@ -0,0 +1,2 @@
|
||||
Huvudsakliga ändringar i den här versionen: Redigering av rumsbehörigheter, automatiskt ljust/mörkt tema, och en hög buggfixar.
|
||||
Full ändringslogg: https://github.com/vector-im/element-android/releases/tag/v1.0.14
|
2
fastlane/metadata/android/sv/changelogs/40100150.txt
Normal file
2
fastlane/metadata/android/sv/changelogs/40100150.txt
Normal file
@ -0,0 +1,2 @@
|
||||
Huvudsakliga ändringar i den här versionen: Stöd för social inloggning.
|
||||
Full ändringslogg: https://github.com/vector-im/element-android/releases/tag/v1.0.15
|
2
fastlane/metadata/android/sv/changelogs/40100160.txt
Normal file
2
fastlane/metadata/android/sv/changelogs/40100160.txt
Normal file
@ -0,0 +1,2 @@
|
||||
Huvudsakliga ändringar i den här versionen: Stöd för social inloggning.
|
||||
Full ändringslogg: https://github.com/vector-im/element-android/releases/tag/v1.0.15 och https://github.com/vector-im/element-android/releases/tag/v1.0.16
|
@ -1,2 +1,2 @@
|
||||
Основні зміни в цій версії: попередній перегляд URL-адреси, нова клавіатура Emoji, нові можливості налаштування кімнати та сніг на Різдво!
|
||||
Повний журнал змін: https://github.com/vector-im/element-android/releases/tag/v1.0.12
|
||||
Основні зміни в цій версії: попередній перегляд URL-адрес, нова клавіатура Emoji, нові можливості налаштування кімнати та сніг на Різдво!
|
||||
Повний перелік змін: https://github.com/vector-im/element-android/releases/tag/v1.0.13
|
||||
|
2
fastlane/metadata/android/uk/changelogs/40100140.txt
Normal file
2
fastlane/metadata/android/uk/changelogs/40100140.txt
Normal file
@ -0,0 +1,2 @@
|
||||
Основні зміни цієї версії: Керування дозволами кімнати, автоперемикання між світлою/темною темами та виправлення багатьох вад.
|
||||
Повний перелік змін: https://github.com/vector-im/element-android/releases/tag/v1.0.14
|
2
fastlane/metadata/android/uk/changelogs/40100150.txt
Normal file
2
fastlane/metadata/android/uk/changelogs/40100150.txt
Normal file
@ -0,0 +1,2 @@
|
||||
Основні зміни цієї версії: підтримка входу за допомогою суспільних мереж.
|
||||
Повний перелік змін: https://github.com/vector-im/element-android/releases/tag/v1.0.15
|
2
fastlane/metadata/android/uk/changelogs/40100160.txt
Normal file
2
fastlane/metadata/android/uk/changelogs/40100160.txt
Normal file
@ -0,0 +1,2 @@
|
||||
Основні зміни цієї версії: підтримка входу за допомогою суспільних мереж.
|
||||
Повний перелік змін: https://github.com/vector-im/element-android/releases/tag/v1.0.15 та https://github.com/vector-im/element-android/releases/tag/v1.0.16
|
@ -1,2 +1,2 @@
|
||||
此版本中的主要變更:URL 預覽、新的表情符號鍵盤、新的聊天室設定功能以及聖誕節降雪!
|
||||
完整變更紀錄:https://github.com/vector-im/element-android/releases/tag/v1.0.12
|
||||
完整變更紀錄:https://github.com/vector-im/element-android/releases/tag/v1.0.13
|
||||
|
@ -0,0 +1,2 @@
|
||||
此版本的主要變動:編輯聊天室權限、自動淺色/深色佈景主題與許多臭蟲修復。
|
||||
完整變更紀錄:https://github.com/vector-im/element-android/releases/tag/v1.0.14
|
@ -0,0 +1,2 @@
|
||||
此版本的主要變動:社群網路登入支援。
|
||||
完整變更紀錄:https://github.com/vector-im/element-android/releases/tag/v1.0.15
|
@ -0,0 +1,2 @@
|
||||
此版本的主要變動:社群網路登入支援。
|
||||
完整變更紀錄:https://github.com/vector-im/element-android/releases/tag/v1.0.15 以及 https://github.com/vector-im/element-android/releases/tag/v1.0.16
|
1
gradle/wrapper/gradle-wrapper.properties
vendored
1
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,3 +1,4 @@
|
||||
#Fri Jan 29 18:05:42 CET 2021
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionSha256Sum=1433372d903ffba27496f8d5af24265310d2da0d78bf6b4e5138831d4fe066e9
|
||||
|
@ -168,12 +168,6 @@ dependencies {
|
||||
// Phone number https://github.com/google/libphonenumber
|
||||
implementation 'com.googlecode.libphonenumber:libphonenumber:8.10.23'
|
||||
|
||||
// Web RTC
|
||||
// org.webrtc:google-webrtc is for development purposes only. See http://webrtc.github.io/webrtc-org/native-code/android/
|
||||
// implementation 'org.webrtc:google-webrtc:1.0.+'
|
||||
// Use the same WebRTC library than the one used by Jitsi library
|
||||
implementation('com.facebook.react:react-native-webrtc:1.84.0-jitsi-5112273@aar')
|
||||
|
||||
testImplementation 'junit:junit:4.13'
|
||||
testImplementation 'org.robolectric:robolectric:4.3'
|
||||
//testImplementation 'org.robolectric:shadows-support-v4:3.0'
|
||||
|
@ -35,7 +35,11 @@ data class MatrixConfiguration(
|
||||
* 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
|
||||
val proxy: Proxy? = null,
|
||||
/**
|
||||
* True to advertise support for call transfers to other parties on Matrix calls.
|
||||
*/
|
||||
val supportsCallTransfer: Boolean = false
|
||||
) {
|
||||
|
||||
/**
|
||||
|
@ -48,6 +48,7 @@ import org.matrix.android.sdk.api.session.signout.SignOutService
|
||||
import org.matrix.android.sdk.api.session.sync.FilterService
|
||||
import org.matrix.android.sdk.api.session.sync.SyncState
|
||||
import org.matrix.android.sdk.api.session.terms.TermsService
|
||||
import org.matrix.android.sdk.api.session.thirdparty.ThirdPartyService
|
||||
import org.matrix.android.sdk.api.session.typing.TypingUsersTracker
|
||||
import org.matrix.android.sdk.api.session.user.UserService
|
||||
import org.matrix.android.sdk.api.session.widgets.WidgetService
|
||||
@ -212,6 +213,11 @@ interface Session :
|
||||
*/
|
||||
fun searchService(): SearchService
|
||||
|
||||
/**
|
||||
* Returns the third party service associated with the session
|
||||
*/
|
||||
fun thirdPartyService(): ThirdPartyService
|
||||
|
||||
/**
|
||||
* Add a listener to the session.
|
||||
* @param listener the listener to add.
|
||||
|
@ -20,8 +20,11 @@ import org.matrix.android.sdk.api.session.room.model.call.CallAnswerContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallCandidatesContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallHangupContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallInviteContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallNegotiateContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallRejectContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallSelectAnswerContent
|
||||
|
||||
interface CallsListener {
|
||||
interface CallListener {
|
||||
/**
|
||||
* Called when there is an incoming call within the room.
|
||||
*/
|
||||
@ -39,5 +42,23 @@ interface CallsListener {
|
||||
*/
|
||||
fun onCallHangupReceived(callHangupContent: CallHangupContent)
|
||||
|
||||
/**
|
||||
* Called when a called has been rejected
|
||||
*/
|
||||
fun onCallRejectReceived(callRejectContent: CallRejectContent)
|
||||
|
||||
/**
|
||||
* Called when an answer has been selected
|
||||
*/
|
||||
fun onCallSelectAnswerReceived(callSelectAnswerContent: CallSelectAnswerContent)
|
||||
|
||||
/**
|
||||
* Called when a negotiation is sent
|
||||
*/
|
||||
fun onCallNegotiateReceived(callNegotiateContent: CallNegotiateContent)
|
||||
|
||||
/**
|
||||
* Called when the call has been managed by an other session
|
||||
*/
|
||||
fun onCallManagedByOtherSession(callId: String)
|
||||
}
|
@ -28,9 +28,9 @@ interface CallSignalingService {
|
||||
*/
|
||||
fun createOutgoingCall(roomId: String, otherUserId: String, isVideoCall: Boolean): MxCall
|
||||
|
||||
fun addCallListener(listener: CallsListener)
|
||||
fun addCallListener(listener: CallListener)
|
||||
|
||||
fun removeCallListener(listener: CallsListener)
|
||||
fun removeCallListener(listener: CallListener)
|
||||
|
||||
fun getCallWithId(callId: String): MxCall?
|
||||
|
||||
|
@ -16,13 +16,16 @@
|
||||
|
||||
package org.matrix.android.sdk.api.session.call
|
||||
|
||||
import org.webrtc.PeerConnection
|
||||
|
||||
sealed class CallState {
|
||||
|
||||
/** Idle, setting up objects */
|
||||
object Idle : CallState()
|
||||
|
||||
/**
|
||||
* CreateOffer. Intermediate state between Idle and Dialing.
|
||||
*/
|
||||
object CreateOffer: CallState()
|
||||
|
||||
/** Dialing. Outgoing call is signaling the remote peer */
|
||||
object Dialing : CallState()
|
||||
|
||||
@ -36,8 +39,8 @@ sealed class CallState {
|
||||
* Connected. Incoming/Outgoing call, ice layer connecting or connected
|
||||
* Notice that the PeerState failed is not always final, if you switch network, new ice candidtates
|
||||
* could be exchanged, and the connection could go back to connected
|
||||
*/
|
||||
data class Connected(val iceConnectionState: PeerConnection.PeerConnectionState) : CallState()
|
||||
* */
|
||||
data class Connected(val iceConnectionState: MxPeerConnectionState) : CallState()
|
||||
|
||||
/** Terminated. Incoming/Outgoing call, the call is terminated */
|
||||
object Terminated : CallState()
|
||||
|
@ -16,14 +16,17 @@
|
||||
|
||||
package org.matrix.android.sdk.api.session.call
|
||||
|
||||
import org.webrtc.IceCandidate
|
||||
import org.webrtc.SessionDescription
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallCandidate
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallCapabilities
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallHangupContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.SdpType
|
||||
import org.matrix.android.sdk.api.util.Optional
|
||||
|
||||
interface MxCallDetail {
|
||||
val callId: String
|
||||
val isOutgoing: Boolean
|
||||
val roomId: String
|
||||
val otherUserId: String
|
||||
val opponentUserId: String
|
||||
val isVideoCall: Boolean
|
||||
}
|
||||
|
||||
@ -32,40 +35,64 @@ interface MxCallDetail {
|
||||
*/
|
||||
interface MxCall : MxCallDetail {
|
||||
|
||||
companion object {
|
||||
const val VOIP_PROTO_VERSION = 1
|
||||
}
|
||||
|
||||
val ourPartyId: String
|
||||
var opponentPartyId: Optional<String>?
|
||||
var opponentVersion: Int
|
||||
|
||||
var capabilities: CallCapabilities?
|
||||
|
||||
var state: CallState
|
||||
|
||||
/**
|
||||
* Pick Up the incoming call
|
||||
* It has no effect on outgoing call
|
||||
*/
|
||||
fun accept(sdp: SessionDescription)
|
||||
fun accept(sdpString: String)
|
||||
|
||||
/**
|
||||
* SDP negotiation for media pause, hold/resume, ICE restarts and voice/video call up/downgrading
|
||||
*/
|
||||
fun negotiate(sdpString: String, type: SdpType)
|
||||
|
||||
/**
|
||||
* This has to be sent by the caller's client once it has chosen an answer.
|
||||
*/
|
||||
fun selectAnswer()
|
||||
|
||||
/**
|
||||
* Reject an incoming call
|
||||
* It's an alias to hangUp
|
||||
*/
|
||||
fun reject() = hangUp()
|
||||
fun reject()
|
||||
|
||||
/**
|
||||
* End the call
|
||||
*/
|
||||
fun hangUp()
|
||||
fun hangUp(reason: CallHangupContent.Reason? = null)
|
||||
|
||||
/**
|
||||
* Start a call
|
||||
* Send offer SDP to the other participant.
|
||||
*/
|
||||
fun offerSdp(sdp: SessionDescription)
|
||||
fun offerSdp(sdpString: String)
|
||||
|
||||
/**
|
||||
* Send Ice candidate to the other participant.
|
||||
* Send Call candidate to the other participant.
|
||||
*/
|
||||
fun sendLocalIceCandidates(candidates: List<IceCandidate>)
|
||||
fun sendLocalCallCandidates(candidates: List<CallCandidate>)
|
||||
|
||||
/**
|
||||
* Send removed ICE candidates to the other participant.
|
||||
*/
|
||||
fun sendLocalIceCandidateRemovals(candidates: List<IceCandidate>)
|
||||
fun sendLocalIceCandidateRemovals(candidates: List<CallCandidate>)
|
||||
|
||||
/**
|
||||
* Send a m.call.replaces event to initiate call transfer.
|
||||
*/
|
||||
suspend fun transfer(targetUserId: String, targetRoomId: String?)
|
||||
|
||||
fun addListener(listener: StateListener)
|
||||
fun removeListener(listener: StateListener)
|
||||
|
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 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.call;
|
||||
|
||||
/**
|
||||
* This is a copy of https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/connectionState
|
||||
* to avoid having the dependency over WebRtc library on sdk.
|
||||
*/
|
||||
public enum MxPeerConnectionState {
|
||||
NEW,
|
||||
CONNECTING,
|
||||
CONNECTED,
|
||||
DISCONNECTED,
|
||||
FAILED,
|
||||
CLOSED
|
||||
}
|
@ -68,7 +68,12 @@ object EventType {
|
||||
const val CALL_INVITE = "m.call.invite"
|
||||
const val CALL_CANDIDATES = "m.call.candidates"
|
||||
const val CALL_ANSWER = "m.call.answer"
|
||||
const val CALL_SELECT_ANSWER = "m.call.select_answer"
|
||||
const val CALL_NEGOTIATE = "m.call.negotiate"
|
||||
const val CALL_REJECT = "m.call.reject"
|
||||
const val CALL_HANGUP = "m.call.hangup"
|
||||
// This type is not processed by the client, just sent to the server
|
||||
const val CALL_REPLACES = "m.call.replaces"
|
||||
|
||||
// Key share events
|
||||
const val ROOM_KEY_REQUEST = "m.room_key_request"
|
||||
@ -98,5 +103,9 @@ object EventType {
|
||||
|| type == CALL_CANDIDATES
|
||||
|| type == CALL_ANSWER
|
||||
|| type == CALL_HANGUP
|
||||
|| type == CALL_SELECT_ANSWER
|
||||
|| type == CALL_NEGOTIATE
|
||||
|| type == CALL_REJECT
|
||||
|| type == CALL_REPLACES
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,6 @@ import org.matrix.android.sdk.api.MatrixCallback
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomDirectoryVisibility
|
||||
import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoomsParams
|
||||
import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoomsResponse
|
||||
import org.matrix.android.sdk.api.session.room.model.thirdparty.ThirdPartyProtocol
|
||||
import org.matrix.android.sdk.api.util.Cancelable
|
||||
|
||||
/**
|
||||
@ -35,12 +34,6 @@ interface RoomDirectoryService {
|
||||
publicRoomsParams: PublicRoomsParams,
|
||||
callback: MatrixCallback<PublicRoomsResponse>): Cancelable
|
||||
|
||||
/**
|
||||
* Fetches the overall metadata about protocols supported by the homeserver.
|
||||
* Includes both the available protocols and all fields required for queries against each protocol.
|
||||
*/
|
||||
fun getThirdPartyProtocol(callback: MatrixCallback<Map<String, ThirdPartyProtocol>>): Cancelable
|
||||
|
||||
/**
|
||||
* Get the visibility of a room in the directory
|
||||
*/
|
||||
|
@ -27,16 +27,24 @@ data class CallAnswerContent(
|
||||
/**
|
||||
* Required. The ID of the call this event relates to.
|
||||
*/
|
||||
@Json(name = "call_id") val callId: String,
|
||||
@Json(name = "call_id") override val callId: String,
|
||||
/**
|
||||
* Required. ID to let user identify remote echo of their own events
|
||||
*/
|
||||
@Json(name = "party_id") override val partyId: String? = null,
|
||||
/**
|
||||
* Required. The session description object
|
||||
*/
|
||||
@Json(name = "answer") val answer: Answer,
|
||||
/**
|
||||
* Required. The version of the VoIP specification this messages adheres to. This specification is version 0.
|
||||
* Required. The version of the VoIP specification this messages adheres to.
|
||||
*/
|
||||
@Json(name = "version") val version: Int = 0
|
||||
) {
|
||||
@Json(name = "version") override val version: String?,
|
||||
/**
|
||||
* Capability advertisement.
|
||||
*/
|
||||
@Json(name = "capabilities") val capabilities: CallCapabilities? = null
|
||||
): CallSignallingContent {
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class Answer(
|
||||
|
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2020 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.matrix.android.sdk.api.session.room.model.call
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class CallCandidate(
|
||||
/**
|
||||
* Required. The SDP media type this candidate is intended for.
|
||||
*/
|
||||
@Json(name = "sdpMid") val sdpMid: String? = null,
|
||||
/**
|
||||
* Required. The index of the SDP 'm' line this candidate is intended for.
|
||||
*/
|
||||
@Json(name = "sdpMLineIndex") val sdpMLineIndex: Int = 0,
|
||||
/**
|
||||
* Required. The SDP 'a' line of the candidate.
|
||||
*/
|
||||
@Json(name = "candidate") val candidate: String? = null
|
||||
)
|
@ -28,30 +28,17 @@ data class CallCandidatesContent(
|
||||
/**
|
||||
* Required. The ID of the call this event relates to.
|
||||
*/
|
||||
@Json(name = "call_id") val callId: String,
|
||||
@Json(name = "call_id") override val callId: String,
|
||||
/**
|
||||
* Required. ID to let user identify remote echo of their own events
|
||||
*/
|
||||
@Json(name = "party_id") override val partyId: String? = null,
|
||||
/**
|
||||
* Required. Array of objects describing the candidates.
|
||||
*/
|
||||
@Json(name = "candidates") val candidates: List<Candidate> = emptyList(),
|
||||
@Json(name = "candidates") val candidates: List<CallCandidate> = emptyList(),
|
||||
/**
|
||||
* Required. The version of the VoIP specification this messages adheres to. This specification is version 0.
|
||||
* Required. The version of the VoIP specification this messages adheres to.
|
||||
*/
|
||||
@Json(name = "version") val version: Int = 0
|
||||
) {
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class Candidate(
|
||||
/**
|
||||
* Required. The SDP media type this candidate is intended for.
|
||||
*/
|
||||
@Json(name = "sdpMid") val sdpMid: String,
|
||||
/**
|
||||
* Required. The index of the SDP 'm' line this candidate is intended for.
|
||||
*/
|
||||
@Json(name = "sdpMLineIndex") val sdpMLineIndex: Int,
|
||||
/**
|
||||
* Required. The SDP 'a' line of the candidate.
|
||||
*/
|
||||
@Json(name = "candidate") val candidate: String
|
||||
)
|
||||
}
|
||||
@Json(name = "version") override val version: String?
|
||||
): CallSignallingContent
|
||||
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.matrix.android.sdk.api.session.room.model.call
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
import org.matrix.android.sdk.api.extensions.orFalse
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class CallCapabilities(
|
||||
/**
|
||||
* If set to true, states that the sender of the event supports the m.call.replaces event and therefore supports
|
||||
* being transferred to another destination
|
||||
*/
|
||||
@Json(name = "m.call.transferee") val transferee: Boolean? = null
|
||||
)
|
||||
|
||||
fun CallCapabilities?.supportCallTransfer() = this?.transferee.orFalse()
|
@ -28,24 +28,41 @@ data class CallHangupContent(
|
||||
/**
|
||||
* Required. The ID of the call this event relates to.
|
||||
*/
|
||||
@Json(name = "call_id") val callId: String,
|
||||
@Json(name = "call_id") override val callId: String,
|
||||
/**
|
||||
* Required. The version of the VoIP specification this message adheres to. This specification is version 0.
|
||||
* Required. ID to let user identify remote echo of their own events
|
||||
*/
|
||||
@Json(name = "version") val version: Int = 0,
|
||||
@Json(name = "party_id") override val partyId: String? = null,
|
||||
/**
|
||||
* Required. The version of the VoIP specification this message adheres to.
|
||||
*/
|
||||
@Json(name = "version") override val version: String?,
|
||||
/**
|
||||
* Optional error reason for the hangup. This should not be provided when the user naturally ends or rejects the call.
|
||||
* When there was an error in the call negotiation, this should be `ice_failed` for when ICE negotiation fails
|
||||
* or `invite_timeout` for when the other party did not answer in time. One of: ["ice_failed", "invite_timeout"]
|
||||
* or `invite_timeout` for when the other party did not answer in time.
|
||||
* One of: ["ice_failed", "invite_timeout"]
|
||||
*/
|
||||
@Json(name = "reason") val reason: Reason? = null
|
||||
) {
|
||||
) : CallSignallingContent {
|
||||
@JsonClass(generateAdapter = false)
|
||||
enum class Reason {
|
||||
@Json(name = "ice_failed")
|
||||
ICE_FAILED,
|
||||
|
||||
@Json(name = "ice_timeout")
|
||||
ICE_TIMEOUT,
|
||||
|
||||
@Json(name = "user_hangup")
|
||||
USER_HANGUP,
|
||||
|
||||
@Json(name = "user_media_failed")
|
||||
USER_MEDIA_FAILED,
|
||||
|
||||
@Json(name = "invite_timeout")
|
||||
INVITE_TIMEOUT
|
||||
INVITE_TIMEOUT,
|
||||
|
||||
@Json(name = "unknown_error")
|
||||
UNKWOWN_ERROR
|
||||
}
|
||||
}
|
||||
|
@ -27,22 +27,35 @@ data class CallInviteContent(
|
||||
/**
|
||||
* Required. A unique identifier for the call.
|
||||
*/
|
||||
@Json(name = "call_id") val callId: String?,
|
||||
@Json(name = "call_id") override val callId: String?,
|
||||
/**
|
||||
* Required. ID to let user identify remote echo of their own events
|
||||
*/
|
||||
@Json(name = "party_id") override val partyId: String? = null,
|
||||
/**
|
||||
* Required. The session description object
|
||||
*/
|
||||
@Json(name = "offer") val offer: Offer?,
|
||||
/**
|
||||
* Required. The version of the VoIP specification this message adheres to. This specification is version 0.
|
||||
* Required. The version of the VoIP specification this message adheres to.
|
||||
*/
|
||||
@Json(name = "version") val version: Int? = 0,
|
||||
@Json(name = "version") override val version: String?,
|
||||
/**
|
||||
* Required. The time in milliseconds that the invite is valid for.
|
||||
* Once the invite age exceeds this value, clients should discard it.
|
||||
* They should also no longer show the call as awaiting an answer in the UI.
|
||||
*/
|
||||
@Json(name = "lifetime") val lifetime: Int?
|
||||
) {
|
||||
@Json(name = "lifetime") val lifetime: Int?,
|
||||
/**
|
||||
* The field should be added for all invites where the target is a specific user
|
||||
*/
|
||||
@Json(name = "invitee") val invitee: String? = null,
|
||||
/**
|
||||
* Capability advertisement.
|
||||
*/
|
||||
@Json(name = "capabilities") val capabilities: CallCapabilities? = null
|
||||
|
||||
): CallSignallingContent {
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class Offer(
|
||||
/**
|
||||
|
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.matrix.android.sdk.api.session.room.model.call
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
/**
|
||||
* This introduces SDP negotiation semantics for media pause, hold/resume, ICE restarts and voice/video call up/downgrading.
|
||||
*/
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class CallNegotiateContent(
|
||||
/**
|
||||
* Required. The ID of the call this event relates to.
|
||||
*/
|
||||
@Json(name = "call_id") override val callId: String,
|
||||
/**
|
||||
* Required. ID to let user identify remote echo of their own events
|
||||
*/
|
||||
@Json(name = "party_id") override val partyId: String? = null,
|
||||
/**
|
||||
* Required. The time in milliseconds that the negotiation is valid for. Once exceeded the sender
|
||||
* of the negotiate event should consider the negotiation failed (timed out) and the recipient should ignore it.
|
||||
**/
|
||||
@Json(name = "lifetime") val lifetime: Int?,
|
||||
/**
|
||||
* Required. The session description object
|
||||
*/
|
||||
@Json(name = "description") val description: Description? = null,
|
||||
|
||||
/**
|
||||
* Required. The version of the VoIP specification this message adheres to.
|
||||
*/
|
||||
@Json(name = "version") override val version: String?
|
||||
|
||||
): CallSignallingContent {
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class Description(
|
||||
/**
|
||||
* Required. The type of session description.
|
||||
*/
|
||||
@Json(name = "type") val type: SdpType?,
|
||||
/**
|
||||
* Required. The SDP text of the session description.
|
||||
*/
|
||||
@Json(name = "sdp") val sdp: String?
|
||||
)
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.matrix.android.sdk.api.session.room.model.call
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
/**
|
||||
* Sent by either party to signal their termination of the call. This can be sent either once
|
||||
* the call has been established or before to abort the call.
|
||||
*/
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class CallRejectContent(
|
||||
/**
|
||||
* Required. The ID of the call this event relates to.
|
||||
*/
|
||||
@Json(name = "call_id") override val callId: String,
|
||||
/**
|
||||
* Required. ID to let user identify remote echo of their own events
|
||||
*/
|
||||
@Json(name = "party_id") override val partyId: String? = null,
|
||||
/**
|
||||
* Required. The version of the VoIP specification this message adheres to.
|
||||
*/
|
||||
@Json(name = "version") override val version: String?
|
||||
) : CallSignallingContent
|
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.matrix.android.sdk.api.session.room.model.call
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
/**
|
||||
* This event is sent to signal the intent of a participant in a call to replace the call with another,
|
||||
* such that the other participant ends up in a call with a new user.
|
||||
*/
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class CallReplacesContent(
|
||||
/**
|
||||
* Required. The ID of the call this event relates to.
|
||||
*/
|
||||
@Json(name = "call_id") override val callId: String,
|
||||
/**
|
||||
* Required. ID to let user identify remote echo of their own events
|
||||
*/
|
||||
@Json(name = "party_id") override val partyId: String? = null,
|
||||
/**
|
||||
* An identifier for the call replacement itself, generated by the transferor.
|
||||
*/
|
||||
@Json(name = "replacement_id") val replacementId: String? = null,
|
||||
/**
|
||||
* Optional. If specified, the transferee client waits for an invite to this room and joins it
|
||||
* (possibly waiting for user confirmation) and then continues the transfer in this room.
|
||||
* If absent, the transferee contacts the Matrix User ID given in the target_user field in a room of its choosing.
|
||||
*/
|
||||
@Json(name = "target_room") val targerRoomId: String? = null,
|
||||
/**
|
||||
* An object giving information about the transfer target
|
||||
*/
|
||||
@Json(name = "target_user") val targetUser: TargetUser? = null,
|
||||
/**
|
||||
* If specified, gives the call ID for the transferee's client to use when placing the replacement call.
|
||||
* Mutually exclusive with await_call
|
||||
*/
|
||||
@Json(name = "create_call") val createCall: String? = null,
|
||||
/**
|
||||
* If specified, gives the call ID that the transferee's client should wait for.
|
||||
* Mutually exclusive with create_call.
|
||||
*/
|
||||
@Json(name = "await_call") val awaitCall: String? = null,
|
||||
/**
|
||||
* Required. The version of the VoIP specification this messages adheres to.
|
||||
*/
|
||||
@Json(name = "version") override val version: String?
|
||||
): CallSignallingContent {
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class TargetUser(
|
||||
/**
|
||||
* Required. The matrix user ID of the transfer target
|
||||
*/
|
||||
@Json(name = "id") val id: String,
|
||||
/**
|
||||
* Optional. The display name of the transfer target.
|
||||
*/
|
||||
@Json(name = "display_name") val displayName: String?,
|
||||
/**
|
||||
* Optional. The avatar URL of the transfer target.
|
||||
*/
|
||||
@Json(name = "avatar_url") val avatarUrl: String?
|
||||
|
||||
)
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.matrix.android.sdk.api.session.room.model.call
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
/**
|
||||
* This event is sent by the callee when they wish to answer the call.
|
||||
*/
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class CallSelectAnswerContent(
|
||||
/**
|
||||
* Required. The ID of the call this event relates to.
|
||||
*/
|
||||
@Json(name = "call_id") override val callId: String,
|
||||
/**
|
||||
* Required. ID to let user identify remote echo of their own events
|
||||
*/
|
||||
@Json(name = "party_id") override val partyId: String? = null,
|
||||
/**
|
||||
* Required. Indicates the answer user has chosen.
|
||||
*/
|
||||
@Json(name = "selected_party_id") val selectedPartyId: String? = null,
|
||||
|
||||
/**
|
||||
* Required. The version of the VoIP specification this message adheres to.
|
||||
*/
|
||||
@Json(name = "version") override val version: String?
|
||||
): CallSignallingContent
|
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2020 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.matrix.android.sdk.api.session.room.model.call
|
||||
|
||||
interface CallSignallingContent {
|
||||
/**
|
||||
* Required. A unique identifier for the call.
|
||||
*/
|
||||
val callId: String?
|
||||
|
||||
/**
|
||||
* Required. ID to let user identify remote echo of their own events
|
||||
*/
|
||||
val partyId: String?
|
||||
|
||||
/**
|
||||
* Required. The version of the VoIP specification this message adheres to. This specification is version 0.
|
||||
*/
|
||||
val version: String?
|
||||
}
|
@ -25,5 +25,5 @@ enum class SdpType {
|
||||
OFFER,
|
||||
|
||||
@Json(name = "answer")
|
||||
ANSWER
|
||||
ANSWER;
|
||||
}
|
||||
|
@ -20,11 +20,15 @@ import org.matrix.android.sdk.api.session.events.model.EventType
|
||||
|
||||
object RoomSummaryConstants {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
val PREVIEWABLE_TYPES = listOf(
|
||||
// TODO filter message type (KEY_VERIFICATION_READY, etc.)
|
||||
EventType.MESSAGE,
|
||||
EventType.CALL_INVITE,
|
||||
EventType.CALL_HANGUP,
|
||||
EventType.CALL_REJECT,
|
||||
EventType.CALL_ANSWER,
|
||||
EventType.ENCRYPTED,
|
||||
EventType.STICKER,
|
||||
|
@ -52,6 +52,8 @@ data class TimelineEvent(
|
||||
}
|
||||
}
|
||||
|
||||
val roomId = root.roomId ?: ""
|
||||
|
||||
val metadata = HashMap<String, Any>()
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2021 The Matrix.org Foundation C.I.C
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.matrix.android.sdk.api.session.thirdparty
|
||||
|
||||
import org.matrix.android.sdk.api.session.room.model.thirdparty.ThirdPartyProtocol
|
||||
import org.matrix.android.sdk.api.session.thirdparty.model.ThirdPartyUser
|
||||
|
||||
/**
|
||||
* See https://matrix.org/docs/spec/client_server/r0.4.0.html#get-matrix-client-r0-thirdparty-protocols
|
||||
*/
|
||||
interface ThirdPartyService {
|
||||
|
||||
/**
|
||||
* Fetches the overall metadata about protocols supported by the homeserver.
|
||||
* Includes both the available protocols and all fields required for queries against each protocol.
|
||||
*/
|
||||
suspend fun getThirdPartyProtocols(): Map<String, ThirdPartyProtocol>
|
||||
|
||||
/**
|
||||
* Retrieve a Matrix User ID linked to a user on the third party service, given a set of user parameters.
|
||||
* @param protocol Required. The name of the protocol.
|
||||
* @param fields One or more custom fields that are passed to the AS to help identify the user.
|
||||
*/
|
||||
suspend fun getThirdPartyUser(protocol: String, fields: Map<String, String> = emptyMap()): List<ThirdPartyUser>
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2021 The Matrix.org Foundation C.I.C
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.matrix.android.sdk.api.session.thirdparty.model
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
import org.matrix.android.sdk.api.util.JsonDict
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class ThirdPartyUser(
|
||||
/*
|
||||
Required. A Matrix User ID represting a third party user.
|
||||
*/
|
||||
@Json(name = "userid") val userId: String,
|
||||
/*
|
||||
Required. The protocol ID that the third party location is a part of.
|
||||
*/
|
||||
@Json(name = "protocol") val protocol: String,
|
||||
/*
|
||||
Required. Information used to identify this third party location.
|
||||
*/
|
||||
@Json(name = "fields") val fields: JsonDict
|
||||
)
|
@ -56,6 +56,11 @@ interface WidgetService {
|
||||
excludedTypes: Set<String>? = null
|
||||
): List<Widget>
|
||||
|
||||
/**
|
||||
* Return the computed URL of a widget
|
||||
*/
|
||||
fun getWidgetComputedUrl(widget: Widget, isLightTheme: Boolean): String?
|
||||
|
||||
/**
|
||||
* Returns the live room widgets so you can listen to them.
|
||||
* Some widgets can be deactivated, so be sure to check for isActive.
|
||||
|
@ -25,7 +25,6 @@ data class Widget(
|
||||
val widgetId: String,
|
||||
val senderInfo: SenderInfo?,
|
||||
val isAddedByMe: Boolean,
|
||||
val computedUrl: String?,
|
||||
val type: WidgetType
|
||||
) {
|
||||
|
||||
|
@ -71,7 +71,6 @@ internal class EventInsertLiveObserver @Inject constructor(@SessionDatabase real
|
||||
return@forEach
|
||||
}
|
||||
val domainEvent = event.asDomain()
|
||||
// decryptIfNeeded(domainEvent)
|
||||
processors.filter {
|
||||
it.shouldProcess(eventId, domainEvent.getClearType(), eventInsert.insertType)
|
||||
}.forEach {
|
||||
@ -83,6 +82,7 @@ internal class EventInsertLiveObserver @Inject constructor(@SessionDatabase real
|
||||
.findAll()
|
||||
.deleteAllFromRealm()
|
||||
}
|
||||
processors.forEach { it.onPostProcess() }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -49,6 +49,7 @@ import org.matrix.android.sdk.api.session.securestorage.SharedSecretStorageServi
|
||||
import org.matrix.android.sdk.api.session.signout.SignOutService
|
||||
import org.matrix.android.sdk.api.session.sync.FilterService
|
||||
import org.matrix.android.sdk.api.session.terms.TermsService
|
||||
import org.matrix.android.sdk.api.session.thirdparty.ThirdPartyService
|
||||
import org.matrix.android.sdk.api.session.typing.TypingUsersTracker
|
||||
import org.matrix.android.sdk.api.session.user.UserService
|
||||
import org.matrix.android.sdk.api.session.widgets.WidgetService
|
||||
@ -114,6 +115,7 @@ internal class DefaultSession @Inject constructor(
|
||||
private val accountService: Lazy<AccountService>,
|
||||
private val defaultIdentityService: DefaultIdentityService,
|
||||
private val integrationManagerService: IntegrationManagerService,
|
||||
private val thirdPartyService: Lazy<ThirdPartyService>,
|
||||
private val callSignalingService: Lazy<CallSignalingService>,
|
||||
@UnauthenticatedWithCertificate
|
||||
private val unauthenticatedWithCertificateOkHttpClient: Lazy<OkHttpClient>,
|
||||
@ -258,6 +260,8 @@ internal class DefaultSession @Inject constructor(
|
||||
|
||||
override fun searchService(): SearchService = searchService.get()
|
||||
|
||||
override fun thirdPartyService(): ThirdPartyService = thirdPartyService.get()
|
||||
|
||||
override fun getOkHttpClient(): OkHttpClient {
|
||||
return unauthenticatedWithCertificateOkHttpClient.get()
|
||||
}
|
||||
|
@ -25,4 +25,12 @@ internal interface EventInsertLiveProcessor {
|
||||
fun shouldProcess(eventId: String, eventType: String, insertType: EventInsertType): Boolean
|
||||
|
||||
suspend fun process(realm: Realm, event: Event)
|
||||
|
||||
/**
|
||||
* Called after transaction.
|
||||
* Maybe you prefer to process the events outside of the realm transaction.
|
||||
*/
|
||||
suspend fun onPostProcess() {
|
||||
// Noop by default
|
||||
}
|
||||
}
|
||||
|
@ -56,6 +56,7 @@ import org.matrix.android.sdk.internal.session.sync.SyncTask
|
||||
import org.matrix.android.sdk.internal.session.sync.SyncTokenStore
|
||||
import org.matrix.android.sdk.internal.session.sync.job.SyncWorker
|
||||
import org.matrix.android.sdk.internal.session.terms.TermsModule
|
||||
import org.matrix.android.sdk.internal.session.thirdparty.ThirdPartyModule
|
||||
import org.matrix.android.sdk.internal.session.user.UserModule
|
||||
import org.matrix.android.sdk.internal.session.user.accountdata.AccountDataModule
|
||||
import org.matrix.android.sdk.internal.session.widgets.WidgetModule
|
||||
@ -87,7 +88,8 @@ import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers
|
||||
ProfileModule::class,
|
||||
AccountModule::class,
|
||||
CallModule::class,
|
||||
SearchModule::class
|
||||
SearchModule::class,
|
||||
ThirdPartyModule::class
|
||||
]
|
||||
)
|
||||
@SessionScope
|
||||
|
@ -16,28 +16,30 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.session.call
|
||||
|
||||
import io.realm.Realm
|
||||
import org.matrix.android.sdk.api.session.events.model.Event
|
||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||
import org.matrix.android.sdk.internal.database.model.EventInsertType
|
||||
import org.matrix.android.sdk.internal.di.UserId
|
||||
import org.matrix.android.sdk.internal.session.EventInsertLiveProcessor
|
||||
import io.realm.Realm
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class CallEventProcessor @Inject constructor(
|
||||
@UserId private val userId: String,
|
||||
private val callService: DefaultCallSignalingService
|
||||
) : EventInsertLiveProcessor {
|
||||
internal class CallEventProcessor @Inject constructor(private val callSignalingHandler: CallSignalingHandler)
|
||||
: EventInsertLiveProcessor {
|
||||
|
||||
private val allowedTypes = listOf(
|
||||
EventType.CALL_ANSWER,
|
||||
EventType.CALL_SELECT_ANSWER,
|
||||
EventType.CALL_REJECT,
|
||||
EventType.CALL_NEGOTIATE,
|
||||
EventType.CALL_CANDIDATES,
|
||||
EventType.CALL_INVITE,
|
||||
EventType.CALL_HANGUP,
|
||||
EventType.ENCRYPTED
|
||||
)
|
||||
|
||||
private val eventsToPostProcess = mutableListOf<Event>()
|
||||
|
||||
override fun shouldProcess(eventId: String, eventType: String, insertType: EventInsertType): Boolean {
|
||||
if (insertType != EventInsertType.INCREMENTAL_SYNC) {
|
||||
return false
|
||||
@ -46,10 +48,17 @@ internal class CallEventProcessor @Inject constructor(
|
||||
}
|
||||
|
||||
override suspend fun process(realm: Realm, event: Event) {
|
||||
update(realm, event)
|
||||
eventsToPostProcess.add(event)
|
||||
}
|
||||
|
||||
private fun update(realm: Realm, event: Event) {
|
||||
override suspend fun onPostProcess() {
|
||||
eventsToPostProcess.forEach {
|
||||
dispatchToCallSignalingHandlerIfNeeded(it)
|
||||
}
|
||||
eventsToPostProcess.clear()
|
||||
}
|
||||
|
||||
private fun dispatchToCallSignalingHandlerIfNeeded(event: Event) {
|
||||
val now = System.currentTimeMillis()
|
||||
// TODO might check if an invite is not closed (hangup/answsered) in the same event batch?
|
||||
event.roomId ?: return Unit.also {
|
||||
@ -60,10 +69,6 @@ internal class CallEventProcessor @Inject constructor(
|
||||
// To old to ring?
|
||||
return
|
||||
}
|
||||
event.ageLocalTs
|
||||
if (EventType.isCallEvent(event.getClearType())) {
|
||||
callService.onCallEvent(event)
|
||||
}
|
||||
Timber.v("$realm : $userId")
|
||||
callSignalingHandler.onCallEvent(event)
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (c) 2020 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.matrix.android.sdk.internal.session.call
|
||||
|
||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||
import org.matrix.android.sdk.api.session.call.CallListener
|
||||
import org.matrix.android.sdk.api.session.call.MxCall
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallAnswerContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallCandidatesContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallHangupContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallInviteContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallNegotiateContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallRejectContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallSelectAnswerContent
|
||||
|
||||
/**
|
||||
* Dispatch each method safely to all listeners.
|
||||
*/
|
||||
internal class CallListenersDispatcher(private val listeners: Set<CallListener>) : CallListener {
|
||||
|
||||
override fun onCallInviteReceived(mxCall: MxCall, callInviteContent: CallInviteContent) = dispatch {
|
||||
it.onCallInviteReceived(mxCall, callInviteContent)
|
||||
}
|
||||
|
||||
override fun onCallIceCandidateReceived(mxCall: MxCall, iceCandidatesContent: CallCandidatesContent) = dispatch {
|
||||
it.onCallIceCandidateReceived(mxCall, iceCandidatesContent)
|
||||
}
|
||||
|
||||
override fun onCallAnswerReceived(callAnswerContent: CallAnswerContent) = dispatch {
|
||||
it.onCallAnswerReceived(callAnswerContent)
|
||||
}
|
||||
|
||||
override fun onCallHangupReceived(callHangupContent: CallHangupContent) = dispatch {
|
||||
it.onCallHangupReceived(callHangupContent)
|
||||
}
|
||||
|
||||
override fun onCallRejectReceived(callRejectContent: CallRejectContent) = dispatch {
|
||||
it.onCallRejectReceived(callRejectContent)
|
||||
}
|
||||
|
||||
override fun onCallManagedByOtherSession(callId: String) = dispatch {
|
||||
it.onCallManagedByOtherSession(callId)
|
||||
}
|
||||
|
||||
override fun onCallSelectAnswerReceived(callSelectAnswerContent: CallSelectAnswerContent) = dispatch {
|
||||
it.onCallSelectAnswerReceived(callSelectAnswerContent)
|
||||
}
|
||||
|
||||
override fun onCallNegotiateReceived(callNegotiateContent: CallNegotiateContent) = dispatch {
|
||||
it.onCallNegotiateReceived(callNegotiateContent)
|
||||
}
|
||||
|
||||
private fun dispatch(lambda: (CallListener) -> Unit) {
|
||||
listeners.toList().forEach {
|
||||
tryOrNull {
|
||||
lambda(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,218 @@
|
||||
/*
|
||||
* Copyright (c) 2020 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.matrix.android.sdk.internal.session.call
|
||||
|
||||
import org.matrix.android.sdk.api.session.call.CallListener
|
||||
import org.matrix.android.sdk.api.session.call.CallState
|
||||
import org.matrix.android.sdk.api.session.call.MxCall
|
||||
import org.matrix.android.sdk.api.session.events.model.Event
|
||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallAnswerContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallCandidatesContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallCapabilities
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallHangupContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallInviteContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallNegotiateContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallRejectContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallSelectAnswerContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallSignallingContent
|
||||
import org.matrix.android.sdk.api.util.Optional
|
||||
import org.matrix.android.sdk.internal.di.UserId
|
||||
import org.matrix.android.sdk.internal.session.SessionScope
|
||||
import timber.log.Timber
|
||||
import java.math.BigDecimal
|
||||
import javax.inject.Inject
|
||||
|
||||
@SessionScope
|
||||
internal class CallSignalingHandler @Inject constructor(private val activeCallHandler: ActiveCallHandler,
|
||||
private val mxCallFactory: MxCallFactory,
|
||||
@UserId private val userId: String) {
|
||||
|
||||
private val callListeners = mutableSetOf<CallListener>()
|
||||
private val callListenersDispatcher = CallListenersDispatcher(callListeners)
|
||||
|
||||
fun addCallListener(listener: CallListener) {
|
||||
callListeners.add(listener)
|
||||
}
|
||||
|
||||
fun removeCallListener(listener: CallListener) {
|
||||
callListeners.remove(listener)
|
||||
}
|
||||
|
||||
fun onCallEvent(event: Event) {
|
||||
when (event.getClearType()) {
|
||||
EventType.CALL_ANSWER -> {
|
||||
handleCallAnswerEvent(event)
|
||||
}
|
||||
EventType.CALL_INVITE -> {
|
||||
handleCallInviteEvent(event)
|
||||
}
|
||||
EventType.CALL_HANGUP -> {
|
||||
handleCallHangupEvent(event)
|
||||
}
|
||||
EventType.CALL_REJECT -> {
|
||||
handleCallRejectEvent(event)
|
||||
}
|
||||
EventType.CALL_CANDIDATES -> {
|
||||
handleCallCandidatesEvent(event)
|
||||
}
|
||||
EventType.CALL_SELECT_ANSWER -> {
|
||||
handleCallSelectAnswerEvent(event)
|
||||
}
|
||||
EventType.CALL_NEGOTIATE -> {
|
||||
handleCallNegotiateEvent(event)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleCallNegotiateEvent(event: Event) {
|
||||
val content = event.getClearContent().toModel<CallNegotiateContent>() ?: return
|
||||
val call = content.getCall() ?: return
|
||||
if (call.ourPartyId == content.partyId) {
|
||||
// Ignore remote echo
|
||||
return
|
||||
}
|
||||
callListenersDispatcher.onCallNegotiateReceived(content)
|
||||
}
|
||||
|
||||
private fun handleCallSelectAnswerEvent(event: Event) {
|
||||
val content = event.getClearContent().toModel<CallSelectAnswerContent>() ?: return
|
||||
val call = content.getCall() ?: return
|
||||
if (call.ourPartyId == content.partyId) {
|
||||
// Ignore remote echo
|
||||
return
|
||||
}
|
||||
if (call.isOutgoing) {
|
||||
Timber.v("Got selectAnswer for an outbound call: ignoring")
|
||||
return
|
||||
}
|
||||
val selectedPartyId = content.selectedPartyId
|
||||
if (selectedPartyId == null) {
|
||||
Timber.w("Got nonsensical select_answer with null selected_party_id: ignoring")
|
||||
return
|
||||
}
|
||||
callListenersDispatcher.onCallSelectAnswerReceived(content)
|
||||
}
|
||||
|
||||
private fun handleCallCandidatesEvent(event: Event) {
|
||||
val content = event.getClearContent().toModel<CallCandidatesContent>() ?: return
|
||||
val call = content.getCall() ?: return
|
||||
if (call.ourPartyId == content.partyId) {
|
||||
// Ignore remote echo
|
||||
return
|
||||
}
|
||||
if (call.opponentPartyId != null && !call.partyIdsMatches(content)) {
|
||||
Timber.v("Ignoring candidates from party ID ${content.partyId} we have chosen party ID ${call.opponentPartyId}")
|
||||
return
|
||||
}
|
||||
callListenersDispatcher.onCallIceCandidateReceived(call, content)
|
||||
}
|
||||
|
||||
private fun handleCallRejectEvent(event: Event) {
|
||||
val content = event.getClearContent().toModel<CallRejectContent>() ?: return
|
||||
val call = content.getCall() ?: return
|
||||
if (call.ourPartyId == content.partyId) {
|
||||
// Ignore remote echo
|
||||
return
|
||||
}
|
||||
activeCallHandler.removeCall(content.callId)
|
||||
if (event.senderId == userId) {
|
||||
// discard current call, it's rejected by another of my session
|
||||
callListenersDispatcher.onCallManagedByOtherSession(content.callId)
|
||||
return
|
||||
}
|
||||
// No need to check party_id for reject because if we'd received either
|
||||
// an answer or reject, we wouldn't be in state InviteSent
|
||||
if (call.state != CallState.Dialing) {
|
||||
return
|
||||
}
|
||||
callListenersDispatcher.onCallRejectReceived(content)
|
||||
}
|
||||
|
||||
private fun handleCallHangupEvent(event: Event) {
|
||||
val content = event.getClearContent().toModel<CallHangupContent>() ?: return
|
||||
val call = content.getCall() ?: return
|
||||
// party ID must match (our chosen partner hanging up the call) or be undefined (we haven't chosen
|
||||
// a partner yet but we're treating the hangup as a reject as per VoIP v0)
|
||||
if (call.opponentPartyId != null && !call.partyIdsMatches(content)) {
|
||||
Timber.v("Ignoring hangup from party ID ${content.partyId} we have chosen party ID ${call.opponentPartyId}")
|
||||
return
|
||||
}
|
||||
if (call.state != CallState.Terminated) {
|
||||
activeCallHandler.removeCall(content.callId)
|
||||
callListenersDispatcher.onCallHangupReceived(content)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleCallInviteEvent(event: Event) {
|
||||
if (event.senderId == userId) {
|
||||
// ignore invites you send
|
||||
return
|
||||
}
|
||||
if (event.roomId == null || event.senderId == null) {
|
||||
return
|
||||
}
|
||||
val content = event.getClearContent().toModel<CallInviteContent>() ?: return
|
||||
val incomingCall = mxCallFactory.createIncomingCall(
|
||||
roomId = event.roomId,
|
||||
opponentUserId = event.senderId,
|
||||
content = content
|
||||
) ?: return
|
||||
activeCallHandler.addCall(incomingCall)
|
||||
callListenersDispatcher.onCallInviteReceived(incomingCall, content)
|
||||
}
|
||||
|
||||
private fun handleCallAnswerEvent(event: Event) {
|
||||
val content = event.getClearContent().toModel<CallAnswerContent>() ?: return
|
||||
val call = content.getCall() ?: return
|
||||
if (call.ourPartyId == content.partyId) {
|
||||
// Ignore remote echo
|
||||
return
|
||||
}
|
||||
if (event.senderId == userId) {
|
||||
// discard current call, it's answered by another of my session
|
||||
activeCallHandler.removeCall(call.callId)
|
||||
callListenersDispatcher.onCallManagedByOtherSession(content.callId)
|
||||
} else {
|
||||
if (call.opponentPartyId != null) {
|
||||
Timber.v("Ignoring answer from party ID ${content.partyId} we already have an answer from ${call.opponentPartyId}")
|
||||
return
|
||||
}
|
||||
call.apply {
|
||||
opponentPartyId = Optional.from(content.partyId)
|
||||
opponentVersion = content.version?.let { BigDecimal(it).intValueExact() } ?: MxCall.VOIP_PROTO_VERSION
|
||||
capabilities = content.capabilities ?: CallCapabilities()
|
||||
}
|
||||
callListenersDispatcher.onCallAnswerReceived(content)
|
||||
}
|
||||
}
|
||||
|
||||
private fun MxCall.partyIdsMatches(contentSignallingContent: CallSignallingContent): Boolean {
|
||||
return opponentPartyId?.getOrNull() == contentSignallingContent.partyId
|
||||
}
|
||||
|
||||
private fun CallSignallingContent.getCall(): MxCall? {
|
||||
val currentCall = callId?.let {
|
||||
activeCallHandler.getCallWithId(it)
|
||||
}
|
||||
if (currentCall == null) {
|
||||
Timber.v("Call with id $callId is null")
|
||||
}
|
||||
return currentCall
|
||||
}
|
||||
}
|
@ -16,106 +16,46 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.session.call
|
||||
|
||||
import android.os.SystemClock
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import org.matrix.android.sdk.api.MatrixCallback
|
||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||
import org.matrix.android.sdk.api.session.call.CallListener
|
||||
import org.matrix.android.sdk.api.session.call.CallSignalingService
|
||||
import org.matrix.android.sdk.api.session.call.CallState
|
||||
import org.matrix.android.sdk.api.session.call.CallsListener
|
||||
import org.matrix.android.sdk.api.session.call.MxCall
|
||||
import org.matrix.android.sdk.api.session.call.TurnServerResponse
|
||||
import org.matrix.android.sdk.api.session.events.model.Event
|
||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallAnswerContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallCandidatesContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallHangupContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallInviteContent
|
||||
import org.matrix.android.sdk.api.util.Cancelable
|
||||
import org.matrix.android.sdk.api.util.NoOpCancellable
|
||||
import org.matrix.android.sdk.internal.di.UserId
|
||||
import org.matrix.android.sdk.internal.session.SessionScope
|
||||
import org.matrix.android.sdk.internal.session.call.model.MxCallImpl
|
||||
import org.matrix.android.sdk.internal.session.room.send.queue.EventSenderProcessor
|
||||
import org.matrix.android.sdk.internal.session.room.send.LocalEchoEventFactory
|
||||
import org.matrix.android.sdk.internal.task.TaskExecutor
|
||||
import org.matrix.android.sdk.internal.task.configureWith
|
||||
import org.matrix.android.sdk.internal.task.launchToCallback
|
||||
import timber.log.Timber
|
||||
import java.util.UUID
|
||||
import javax.inject.Inject
|
||||
|
||||
@SessionScope
|
||||
internal class DefaultCallSignalingService @Inject constructor(
|
||||
@UserId
|
||||
private val userId: String,
|
||||
private val callSignalingHandler: CallSignalingHandler,
|
||||
private val mxCallFactory: MxCallFactory,
|
||||
private val activeCallHandler: ActiveCallHandler,
|
||||
private val localEchoEventFactory: LocalEchoEventFactory,
|
||||
private val eventSenderProcessor: EventSenderProcessor,
|
||||
private val taskExecutor: TaskExecutor,
|
||||
private val turnServerTask: GetTurnServerTask
|
||||
private val turnServerDataSource: TurnServerDataSource
|
||||
) : CallSignalingService {
|
||||
|
||||
private val callListeners = mutableSetOf<CallsListener>()
|
||||
|
||||
private val cachedTurnServerResponse = object {
|
||||
// Keep one minute safe to avoid considering the data is valid and then actually it is not when effectively using it.
|
||||
private val MIN_TTL = 60
|
||||
|
||||
private val now = { SystemClock.elapsedRealtime() / 1000 }
|
||||
|
||||
private var expiresAt: Long = 0
|
||||
|
||||
var data: TurnServerResponse? = null
|
||||
get() = if (expiresAt > now()) field else null
|
||||
set(value) {
|
||||
expiresAt = now() + (value?.ttl ?: 0) - MIN_TTL
|
||||
field = value
|
||||
}
|
||||
}
|
||||
|
||||
override fun getTurnServer(callback: MatrixCallback<TurnServerResponse>): Cancelable {
|
||||
if (cachedTurnServerResponse.data != null) {
|
||||
cachedTurnServerResponse.data?.let { callback.onSuccess(it) }
|
||||
return NoOpCancellable
|
||||
return taskExecutor.executorScope.launchToCallback(Dispatchers.Default, callback) {
|
||||
turnServerDataSource.getTurnServer()
|
||||
}
|
||||
return turnServerTask
|
||||
.configureWith(GetTurnServerTask.Params) {
|
||||
this.callback = object : MatrixCallback<TurnServerResponse> {
|
||||
override fun onSuccess(data: TurnServerResponse) {
|
||||
cachedTurnServerResponse.data = data
|
||||
callback.onSuccess(data)
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
callback.onFailure(failure)
|
||||
}
|
||||
}
|
||||
}
|
||||
.executeBy(taskExecutor)
|
||||
}
|
||||
|
||||
override fun createOutgoingCall(roomId: String, otherUserId: String, isVideoCall: Boolean): MxCall {
|
||||
val call = MxCallImpl(
|
||||
callId = UUID.randomUUID().toString(),
|
||||
isOutgoing = true,
|
||||
roomId = roomId,
|
||||
userId = userId,
|
||||
otherUserId = otherUserId,
|
||||
isVideoCall = isVideoCall,
|
||||
localEchoEventFactory = localEchoEventFactory,
|
||||
eventSenderProcessor = eventSenderProcessor
|
||||
)
|
||||
activeCallHandler.addCall(call).also {
|
||||
return call
|
||||
return mxCallFactory.createOutgoingCall(roomId, otherUserId, isVideoCall).also {
|
||||
activeCallHandler.addCall(it)
|
||||
}
|
||||
}
|
||||
|
||||
override fun addCallListener(listener: CallsListener) {
|
||||
callListeners.add(listener)
|
||||
override fun addCallListener(listener: CallListener) {
|
||||
callSignalingHandler.addCallListener(listener)
|
||||
}
|
||||
|
||||
override fun removeCallListener(listener: CallsListener) {
|
||||
callListeners.remove(listener)
|
||||
override fun removeCallListener(listener: CallListener) {
|
||||
callSignalingHandler.removeCallListener(listener)
|
||||
}
|
||||
|
||||
override fun getCallWithId(callId: String): MxCall? {
|
||||
@ -127,129 +67,6 @@ internal class DefaultCallSignalingService @Inject constructor(
|
||||
return activeCallHandler.getActiveCallsLiveData().value?.isNotEmpty() == true
|
||||
}
|
||||
|
||||
internal fun onCallEvent(event: Event) {
|
||||
when (event.getClearType()) {
|
||||
EventType.CALL_ANSWER -> {
|
||||
event.getClearContent().toModel<CallAnswerContent>()?.let {
|
||||
if (event.senderId == userId) {
|
||||
// ok it's an answer from me.. is it remote echo or other session
|
||||
val knownCall = getCallWithId(it.callId)
|
||||
if (knownCall == null) {
|
||||
Timber.d("## VOIP onCallEvent ${event.getClearType()} id ${it.callId} send by me")
|
||||
} else if (!knownCall.isOutgoing) {
|
||||
// incoming call
|
||||
// if it was anwsered by this session, the call state would be in Answering(or connected) state
|
||||
if (knownCall.state == CallState.LocalRinging) {
|
||||
// discard current call, it's answered by another of my session
|
||||
onCallManageByOtherSession(it.callId)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
onCallAnswer(it)
|
||||
}
|
||||
}
|
||||
EventType.CALL_INVITE -> {
|
||||
if (event.senderId == userId) {
|
||||
// Always ignore local echos of invite
|
||||
return
|
||||
}
|
||||
|
||||
event.getClearContent().toModel<CallInviteContent>()?.let { content ->
|
||||
val incomingCall = MxCallImpl(
|
||||
callId = content.callId ?: return@let,
|
||||
isOutgoing = false,
|
||||
roomId = event.roomId ?: return@let,
|
||||
userId = userId,
|
||||
otherUserId = event.senderId ?: return@let,
|
||||
isVideoCall = content.isVideo(),
|
||||
localEchoEventFactory = localEchoEventFactory,
|
||||
eventSenderProcessor = eventSenderProcessor
|
||||
)
|
||||
activeCallHandler.addCall(incomingCall)
|
||||
onCallInvite(incomingCall, content)
|
||||
}
|
||||
}
|
||||
EventType.CALL_HANGUP -> {
|
||||
event.getClearContent().toModel<CallHangupContent>()?.let { content ->
|
||||
|
||||
if (event.senderId == userId) {
|
||||
// ok it's an answer from me.. is it remote echo or other session
|
||||
val knownCall = getCallWithId(content.callId)
|
||||
if (knownCall == null) {
|
||||
Timber.d("## VOIP onCallEvent ${event.getClearType()} id ${content.callId} send by me")
|
||||
} else if (!knownCall.isOutgoing) {
|
||||
// incoming call
|
||||
if (knownCall.state == CallState.LocalRinging) {
|
||||
// discard current call, it's answered by another of my session
|
||||
onCallManageByOtherSession(content.callId)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
activeCallHandler.removeCall(content.callId)
|
||||
onCallHangup(content)
|
||||
}
|
||||
}
|
||||
EventType.CALL_CANDIDATES -> {
|
||||
if (event.senderId == userId) {
|
||||
// Always ignore local echos of invite
|
||||
return
|
||||
}
|
||||
event.getClearContent().toModel<CallCandidatesContent>()?.let { content ->
|
||||
activeCallHandler.getCallWithId(content.callId)?.let {
|
||||
onCallIceCandidate(it, content)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun onCallHangup(hangup: CallHangupContent) {
|
||||
callListeners.toList().forEach {
|
||||
tryOrNull {
|
||||
it.onCallHangupReceived(hangup)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun onCallAnswer(answer: CallAnswerContent) {
|
||||
callListeners.toList().forEach {
|
||||
tryOrNull {
|
||||
it.onCallAnswerReceived(answer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun onCallManageByOtherSession(callId: String) {
|
||||
callListeners.toList().forEach {
|
||||
tryOrNull {
|
||||
it.onCallManagedByOtherSession(callId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun onCallInvite(incomingCall: MxCall, invite: CallInviteContent) {
|
||||
// Ignore the invitation from current user
|
||||
if (incomingCall.otherUserId == userId) return
|
||||
|
||||
callListeners.toList().forEach {
|
||||
tryOrNull {
|
||||
it.onCallInviteReceived(incomingCall, invite)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun onCallIceCandidate(incomingCall: MxCall, candidates: CallCandidatesContent) {
|
||||
callListeners.toList().forEach {
|
||||
tryOrNull {
|
||||
it.onCallIceCandidateReceived(incomingCall, candidates)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val CALL_TIMEOUT_MS = 120_000
|
||||
}
|
||||
|
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (c) 2020 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.matrix.android.sdk.internal.session.call
|
||||
|
||||
import org.matrix.android.sdk.api.MatrixConfiguration
|
||||
import org.matrix.android.sdk.api.session.call.MxCall
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallCapabilities
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallInviteContent
|
||||
import org.matrix.android.sdk.api.util.Optional
|
||||
import org.matrix.android.sdk.internal.di.DeviceId
|
||||
import org.matrix.android.sdk.internal.di.UserId
|
||||
import org.matrix.android.sdk.internal.session.call.model.MxCallImpl
|
||||
import org.matrix.android.sdk.internal.session.profile.GetProfileInfoTask
|
||||
import org.matrix.android.sdk.internal.session.room.send.LocalEchoEventFactory
|
||||
import org.matrix.android.sdk.internal.session.room.send.queue.EventSenderProcessor
|
||||
import java.math.BigDecimal
|
||||
import java.util.UUID
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class MxCallFactory @Inject constructor(
|
||||
@DeviceId private val deviceId: String?,
|
||||
private val localEchoEventFactory: LocalEchoEventFactory,
|
||||
private val eventSenderProcessor: EventSenderProcessor,
|
||||
private val matrixConfiguration: MatrixConfiguration,
|
||||
private val getProfileInfoTask: GetProfileInfoTask,
|
||||
@UserId private val userId: String
|
||||
) {
|
||||
|
||||
fun createIncomingCall(roomId: String, opponentUserId: String, content: CallInviteContent): MxCall? {
|
||||
content.callId ?: return null
|
||||
return MxCallImpl(
|
||||
callId = content.callId,
|
||||
isOutgoing = false,
|
||||
roomId = roomId,
|
||||
userId = userId,
|
||||
ourPartyId = deviceId ?: "",
|
||||
opponentUserId = opponentUserId,
|
||||
isVideoCall = content.isVideo(),
|
||||
localEchoEventFactory = localEchoEventFactory,
|
||||
eventSenderProcessor = eventSenderProcessor,
|
||||
matrixConfiguration = matrixConfiguration,
|
||||
getProfileInfoTask = getProfileInfoTask
|
||||
).apply {
|
||||
opponentPartyId = Optional.from(content.partyId)
|
||||
opponentVersion = content.version?.let { BigDecimal(it).intValueExact() } ?: MxCall.VOIP_PROTO_VERSION
|
||||
capabilities = content.capabilities ?: CallCapabilities()
|
||||
}
|
||||
}
|
||||
|
||||
fun createOutgoingCall(roomId: String, opponentUserId: String, isVideoCall: Boolean): MxCall {
|
||||
return MxCallImpl(
|
||||
callId = UUID.randomUUID().toString(),
|
||||
isOutgoing = true,
|
||||
roomId = roomId,
|
||||
userId = userId,
|
||||
ourPartyId = deviceId ?: "",
|
||||
opponentUserId = opponentUserId,
|
||||
isVideoCall = isVideoCall,
|
||||
localEchoEventFactory = localEchoEventFactory,
|
||||
eventSenderProcessor = eventSenderProcessor,
|
||||
matrixConfiguration = matrixConfiguration,
|
||||
getProfileInfoTask = getProfileInfoTask
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2020 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.matrix.android.sdk.internal.session.call
|
||||
|
||||
import android.os.SystemClock
|
||||
import org.matrix.android.sdk.api.session.call.TurnServerResponse
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class TurnServerDataSource @Inject constructor(private val turnServerTask: GetTurnServerTask) {
|
||||
|
||||
private val cachedTurnServerResponse = object {
|
||||
// Keep one minute safe to avoid considering the data is valid and then actually it is not when effectively using it.
|
||||
private val MIN_TTL = 60
|
||||
|
||||
private val now = { SystemClock.elapsedRealtime() / 1000 }
|
||||
|
||||
private var expiresAt: Long = 0
|
||||
|
||||
var data: TurnServerResponse? = null
|
||||
get() = if (expiresAt > now()) field else null
|
||||
set(value) {
|
||||
expiresAt = now() + (value?.ttl ?: 0) - MIN_TTL
|
||||
field = value
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getTurnServer(): TurnServerResponse {
|
||||
return cachedTurnServerResponse.data ?: turnServerTask.execute(GetTurnServerTask.Params).also {
|
||||
cachedTurnServerResponse.data = it
|
||||
}
|
||||
}
|
||||
}
|
@ -16,6 +16,7 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.session.call.model
|
||||
|
||||
import org.matrix.android.sdk.api.MatrixConfiguration
|
||||
import org.matrix.android.sdk.api.session.call.CallState
|
||||
import org.matrix.android.sdk.api.session.call.MxCall
|
||||
import org.matrix.android.sdk.api.session.events.model.Content
|
||||
@ -24,28 +25,44 @@ import org.matrix.android.sdk.api.session.events.model.EventType
|
||||
import org.matrix.android.sdk.api.session.events.model.LocalEcho
|
||||
import org.matrix.android.sdk.api.session.events.model.UnsignedData
|
||||
import org.matrix.android.sdk.api.session.events.model.toContent
|
||||
import org.matrix.android.sdk.api.session.profile.ProfileService
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallAnswerContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallCandidate
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallCandidatesContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallCapabilities
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallHangupContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallInviteContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallNegotiateContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallRejectContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallReplacesContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallSelectAnswerContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.SdpType
|
||||
import org.matrix.android.sdk.api.util.Optional
|
||||
import org.matrix.android.sdk.internal.session.call.DefaultCallSignalingService
|
||||
import org.matrix.android.sdk.internal.session.room.send.queue.EventSenderProcessor
|
||||
import org.matrix.android.sdk.internal.session.profile.GetProfileInfoTask
|
||||
import org.matrix.android.sdk.internal.session.room.send.LocalEchoEventFactory
|
||||
import org.webrtc.IceCandidate
|
||||
import org.webrtc.SessionDescription
|
||||
import org.matrix.android.sdk.internal.session.room.send.queue.EventSenderProcessor
|
||||
import timber.log.Timber
|
||||
import java.util.UUID
|
||||
|
||||
internal class MxCallImpl(
|
||||
override val callId: String,
|
||||
override val isOutgoing: Boolean,
|
||||
override val roomId: String,
|
||||
private val userId: String,
|
||||
override val otherUserId: String,
|
||||
override val opponentUserId: String,
|
||||
override val isVideoCall: Boolean,
|
||||
override val ourPartyId: String,
|
||||
private val localEchoEventFactory: LocalEchoEventFactory,
|
||||
private val eventSenderProcessor: EventSenderProcessor
|
||||
private val eventSenderProcessor: EventSenderProcessor,
|
||||
private val matrixConfiguration: MatrixConfiguration,
|
||||
private val getProfileInfoTask: GetProfileInfoTask
|
||||
) : MxCall {
|
||||
|
||||
override var opponentPartyId: Optional<String>? = null
|
||||
override var opponentVersion: Int = MxCall.VOIP_PROTO_VERSION
|
||||
override var capabilities: CallCapabilities? = null
|
||||
|
||||
override var state: CallState = CallState.Idle
|
||||
set(value) {
|
||||
field = value
|
||||
@ -81,60 +98,135 @@ internal class MxCallImpl(
|
||||
}
|
||||
}
|
||||
|
||||
override fun offerSdp(sdp: SessionDescription) {
|
||||
override fun offerSdp(sdpString: String) {
|
||||
if (!isOutgoing) return
|
||||
Timber.v("## VOIP offerSdp $callId")
|
||||
state = CallState.Dialing
|
||||
CallInviteContent(
|
||||
callId = callId,
|
||||
partyId = ourPartyId,
|
||||
lifetime = DefaultCallSignalingService.CALL_TIMEOUT_MS,
|
||||
offer = CallInviteContent.Offer(sdp = sdp.description)
|
||||
offer = CallInviteContent.Offer(sdp = sdpString),
|
||||
version = MxCall.VOIP_PROTO_VERSION.toString(),
|
||||
capabilities = buildCapabilities()
|
||||
)
|
||||
.let { createEventAndLocalEcho(type = EventType.CALL_INVITE, roomId = roomId, content = it.toContent()) }
|
||||
.also { eventSenderProcessor.postEvent(it) }
|
||||
}
|
||||
|
||||
override fun sendLocalIceCandidates(candidates: List<IceCandidate>) {
|
||||
override fun sendLocalCallCandidates(candidates: List<CallCandidate>) {
|
||||
Timber.v("Send local call canditates $callId: $candidates")
|
||||
CallCandidatesContent(
|
||||
callId = callId,
|
||||
candidates = candidates.map {
|
||||
CallCandidatesContent.Candidate(
|
||||
sdpMid = it.sdpMid,
|
||||
sdpMLineIndex = it.sdpMLineIndex,
|
||||
candidate = it.sdp
|
||||
)
|
||||
}
|
||||
partyId = ourPartyId,
|
||||
candidates = candidates,
|
||||
version = MxCall.VOIP_PROTO_VERSION.toString()
|
||||
)
|
||||
.let { createEventAndLocalEcho(type = EventType.CALL_CANDIDATES, roomId = roomId, content = it.toContent()) }
|
||||
.also { eventSenderProcessor.postEvent(it) }
|
||||
}
|
||||
|
||||
override fun sendLocalIceCandidateRemovals(candidates: List<IceCandidate>) {
|
||||
override fun sendLocalIceCandidateRemovals(candidates: List<CallCandidate>) {
|
||||
// For now we don't support this flow
|
||||
}
|
||||
|
||||
override fun hangUp() {
|
||||
override fun reject() {
|
||||
if (opponentVersion < 1) {
|
||||
Timber.v("Opponent version is less than 1 ($opponentVersion): sending hangup instead of reject")
|
||||
hangUp()
|
||||
return
|
||||
}
|
||||
Timber.v("## VOIP reject $callId")
|
||||
CallRejectContent(
|
||||
callId = callId,
|
||||
partyId = ourPartyId,
|
||||
version = MxCall.VOIP_PROTO_VERSION.toString()
|
||||
)
|
||||
.let { createEventAndLocalEcho(type = EventType.CALL_REJECT, roomId = roomId, content = it.toContent()) }
|
||||
.also { eventSenderProcessor.postEvent(it) }
|
||||
state = CallState.Terminated
|
||||
}
|
||||
|
||||
override fun hangUp(reason: CallHangupContent.Reason?) {
|
||||
Timber.v("## VOIP hangup $callId")
|
||||
CallHangupContent(
|
||||
callId = callId
|
||||
callId = callId,
|
||||
partyId = ourPartyId,
|
||||
reason = reason ?: CallHangupContent.Reason.USER_HANGUP,
|
||||
version = MxCall.VOIP_PROTO_VERSION.toString()
|
||||
)
|
||||
.let { createEventAndLocalEcho(type = EventType.CALL_HANGUP, roomId = roomId, content = it.toContent()) }
|
||||
.also { eventSenderProcessor.postEvent(it) }
|
||||
state = CallState.Terminated
|
||||
}
|
||||
|
||||
override fun accept(sdp: SessionDescription) {
|
||||
override fun accept(sdpString: String) {
|
||||
Timber.v("## VOIP accept $callId")
|
||||
if (isOutgoing) return
|
||||
state = CallState.Answering
|
||||
CallAnswerContent(
|
||||
callId = callId,
|
||||
answer = CallAnswerContent.Answer(sdp = sdp.description)
|
||||
partyId = ourPartyId,
|
||||
answer = CallAnswerContent.Answer(sdp = sdpString),
|
||||
version = MxCall.VOIP_PROTO_VERSION.toString(),
|
||||
capabilities = buildCapabilities()
|
||||
)
|
||||
.let { createEventAndLocalEcho(type = EventType.CALL_ANSWER, roomId = roomId, content = it.toContent()) }
|
||||
.also { eventSenderProcessor.postEvent(it) }
|
||||
}
|
||||
|
||||
override fun negotiate(sdpString: String, type: SdpType) {
|
||||
Timber.v("## VOIP negotiate $callId")
|
||||
CallNegotiateContent(
|
||||
callId = callId,
|
||||
partyId = ourPartyId,
|
||||
lifetime = DefaultCallSignalingService.CALL_TIMEOUT_MS,
|
||||
description = CallNegotiateContent.Description(sdp = sdpString, type = type),
|
||||
version = MxCall.VOIP_PROTO_VERSION.toString()
|
||||
)
|
||||
.let { createEventAndLocalEcho(type = EventType.CALL_NEGOTIATE, roomId = roomId, content = it.toContent()) }
|
||||
.also { eventSenderProcessor.postEvent(it) }
|
||||
}
|
||||
|
||||
override fun selectAnswer() {
|
||||
Timber.v("## VOIP select answer $callId")
|
||||
if (isOutgoing) return
|
||||
state = CallState.Answering
|
||||
CallSelectAnswerContent(
|
||||
callId = callId,
|
||||
partyId = ourPartyId,
|
||||
selectedPartyId = opponentPartyId?.getOrNull(),
|
||||
version = MxCall.VOIP_PROTO_VERSION.toString()
|
||||
)
|
||||
.let { createEventAndLocalEcho(type = EventType.CALL_SELECT_ANSWER, roomId = roomId, content = it.toContent()) }
|
||||
.also { eventSenderProcessor.postEvent(it) }
|
||||
}
|
||||
|
||||
override suspend fun transfer(targetUserId: String, targetRoomId: String?) {
|
||||
val profileInfoParams = GetProfileInfoTask.Params(targetUserId)
|
||||
val profileInfo = try {
|
||||
getProfileInfoTask.execute(profileInfoParams)
|
||||
} catch (failure: Throwable) {
|
||||
Timber.v("Fail fetching profile info of $targetUserId while transferring call")
|
||||
null
|
||||
}
|
||||
CallReplacesContent(
|
||||
callId = callId,
|
||||
partyId = ourPartyId,
|
||||
replacementId = UUID.randomUUID().toString(),
|
||||
version = MxCall.VOIP_PROTO_VERSION.toString(),
|
||||
targetUser = CallReplacesContent.TargetUser(
|
||||
id = targetUserId,
|
||||
displayName = profileInfo?.get(ProfileService.DISPLAY_NAME_KEY) as? String,
|
||||
avatarUrl = profileInfo?.get(ProfileService.AVATAR_URL_KEY) as? String
|
||||
),
|
||||
targerRoomId = targetRoomId,
|
||||
createCall = UUID.randomUUID().toString()
|
||||
)
|
||||
.let { createEventAndLocalEcho(type = EventType.CALL_REPLACES, roomId = roomId, content = it.toContent()) }
|
||||
.also { eventSenderProcessor.postEvent(it) }
|
||||
}
|
||||
|
||||
private fun createEventAndLocalEcho(localId: String = LocalEcho.createLocalEchoId(), type: String, roomId: String, content: Content): Event {
|
||||
return Event(
|
||||
roomId = roomId,
|
||||
@ -147,4 +239,12 @@ internal class MxCallImpl(
|
||||
)
|
||||
.also { localEchoEventFactory.createLocalEcho(it) }
|
||||
}
|
||||
|
||||
private fun buildCapabilities(): CallCapabilities? {
|
||||
return if (matrixConfiguration.supportsCallTransfer) {
|
||||
CallCapabilities(true)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,6 @@ import org.matrix.android.sdk.internal.session.user.accountdata.AccountDataDataS
|
||||
import org.matrix.android.sdk.internal.session.user.accountdata.UpdateUserAccountDataTask
|
||||
import org.matrix.android.sdk.internal.session.widgets.helper.WidgetFactory
|
||||
import org.matrix.android.sdk.internal.session.widgets.helper.extractWidgetSequence
|
||||
import org.matrix.android.sdk.internal.task.TaskExecutor
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
@ -55,7 +54,6 @@ import javax.inject.Inject
|
||||
*/
|
||||
@SessionScope
|
||||
internal class IntegrationManager @Inject constructor(matrixConfiguration: MatrixConfiguration,
|
||||
private val taskExecutor: TaskExecutor,
|
||||
@SessionDatabase private val monarchy: Monarchy,
|
||||
private val updateUserAccountDataTask: UpdateUserAccountDataTask,
|
||||
private val accountDataDataSource: AccountDataDataSource,
|
||||
|
@ -21,11 +21,9 @@ import org.matrix.android.sdk.api.session.room.RoomDirectoryService
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomDirectoryVisibility
|
||||
import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoomsParams
|
||||
import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoomsResponse
|
||||
import org.matrix.android.sdk.api.session.room.model.thirdparty.ThirdPartyProtocol
|
||||
import org.matrix.android.sdk.api.util.Cancelable
|
||||
import org.matrix.android.sdk.internal.session.room.directory.GetPublicRoomTask
|
||||
import org.matrix.android.sdk.internal.session.room.directory.GetRoomDirectoryVisibilityTask
|
||||
import org.matrix.android.sdk.internal.session.room.directory.GetThirdPartyProtocolsTask
|
||||
import org.matrix.android.sdk.internal.session.room.directory.SetRoomDirectoryVisibilityTask
|
||||
import org.matrix.android.sdk.internal.task.TaskExecutor
|
||||
import org.matrix.android.sdk.internal.task.configureWith
|
||||
@ -33,7 +31,6 @@ import javax.inject.Inject
|
||||
|
||||
internal class DefaultRoomDirectoryService @Inject constructor(
|
||||
private val getPublicRoomTask: GetPublicRoomTask,
|
||||
private val getThirdPartyProtocolsTask: GetThirdPartyProtocolsTask,
|
||||
private val getRoomDirectoryVisibilityTask: GetRoomDirectoryVisibilityTask,
|
||||
private val setRoomDirectoryVisibilityTask: SetRoomDirectoryVisibilityTask,
|
||||
private val taskExecutor: TaskExecutor) : RoomDirectoryService {
|
||||
@ -48,14 +45,6 @@ internal class DefaultRoomDirectoryService @Inject constructor(
|
||||
.executeBy(taskExecutor)
|
||||
}
|
||||
|
||||
override fun getThirdPartyProtocol(callback: MatrixCallback<Map<String, ThirdPartyProtocol>>): Cancelable {
|
||||
return getThirdPartyProtocolsTask
|
||||
.configureWith {
|
||||
this.callback = callback
|
||||
}
|
||||
.executeBy(taskExecutor)
|
||||
}
|
||||
|
||||
override suspend fun getRoomDirectoryVisibility(roomId: String): RoomDirectoryVisibility {
|
||||
return getRoomDirectoryVisibilityTask.execute(GetRoomDirectoryVisibilityTask.Params(roomId))
|
||||
}
|
||||
|
@ -20,7 +20,6 @@ import org.matrix.android.sdk.api.session.events.model.Content
|
||||
import org.matrix.android.sdk.api.session.events.model.Event
|
||||
import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoomsParams
|
||||
import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoomsResponse
|
||||
import org.matrix.android.sdk.api.session.room.model.thirdparty.ThirdPartyProtocol
|
||||
import org.matrix.android.sdk.api.util.JsonDict
|
||||
import org.matrix.android.sdk.internal.network.NetworkConstants
|
||||
import org.matrix.android.sdk.internal.session.room.alias.GetAliasesResponse
|
||||
@ -50,14 +49,6 @@ import retrofit2.http.Query
|
||||
|
||||
internal interface RoomAPI {
|
||||
|
||||
/**
|
||||
* Get the third party server protocols.
|
||||
*
|
||||
* Ref: https://matrix.org/docs/spec/client_server/r0.4.0.html#get-matrix-client-r0-thirdparty-protocols
|
||||
*/
|
||||
@GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "thirdparty/protocols")
|
||||
fun thirdPartyProtocols(): Call<Map<String, ThirdPartyProtocol>>
|
||||
|
||||
/**
|
||||
* Lists the public rooms on the server, with optional filter.
|
||||
* This API returns paginated responses. The rooms are ordered by the number of joined members, with the largest rooms first.
|
||||
|
@ -39,11 +39,9 @@ import org.matrix.android.sdk.internal.session.room.create.CreateRoomTask
|
||||
import org.matrix.android.sdk.internal.session.room.create.DefaultCreateRoomTask
|
||||
import org.matrix.android.sdk.internal.session.room.directory.DefaultGetPublicRoomTask
|
||||
import org.matrix.android.sdk.internal.session.room.directory.DefaultGetRoomDirectoryVisibilityTask
|
||||
import org.matrix.android.sdk.internal.session.room.directory.DefaultGetThirdPartyProtocolsTask
|
||||
import org.matrix.android.sdk.internal.session.room.directory.DefaultSetRoomDirectoryVisibilityTask
|
||||
import org.matrix.android.sdk.internal.session.room.directory.GetPublicRoomTask
|
||||
import org.matrix.android.sdk.internal.session.room.directory.GetRoomDirectoryVisibilityTask
|
||||
import org.matrix.android.sdk.internal.session.room.directory.GetThirdPartyProtocolsTask
|
||||
import org.matrix.android.sdk.internal.session.room.directory.SetRoomDirectoryVisibilityTask
|
||||
import org.matrix.android.sdk.internal.session.room.membership.DefaultLoadRoomMembersTask
|
||||
import org.matrix.android.sdk.internal.session.room.membership.LoadRoomMembersTask
|
||||
@ -153,9 +151,6 @@ internal abstract class RoomModule {
|
||||
@Binds
|
||||
abstract fun bindSetRoomDirectoryVisibilityTask(task: DefaultSetRoomDirectoryVisibilityTask): SetRoomDirectoryVisibilityTask
|
||||
|
||||
@Binds
|
||||
abstract fun bindGetThirdPartyProtocolsTask(task: DefaultGetThirdPartyProtocolsTask): GetThirdPartyProtocolsTask
|
||||
|
||||
@Binds
|
||||
abstract fun bindInviteTask(task: DefaultInviteTask): InviteTask
|
||||
|
||||
|
@ -49,8 +49,10 @@ internal class QueueMemento @Inject constructor(context: Context,
|
||||
}
|
||||
|
||||
fun unTrack(task: QueuedTask) {
|
||||
managedTaskInfos.remove(task)
|
||||
persist()
|
||||
synchronized(managedTaskInfos) {
|
||||
managedTaskInfos.remove(task)
|
||||
persist()
|
||||
}
|
||||
}
|
||||
|
||||
private fun persist() {
|
||||
@ -64,19 +66,17 @@ internal class QueueMemento @Inject constructor(context: Context,
|
||||
}
|
||||
|
||||
private fun toTaskInfo(task: QueuedTask, order: Int): TaskInfo? {
|
||||
synchronized(managedTaskInfos) {
|
||||
return when (task) {
|
||||
is SendEventQueuedTask -> SendEventTaskInfo(
|
||||
localEchoId = task.event.eventId ?: "",
|
||||
encrypt = task.encrypt,
|
||||
order = order
|
||||
)
|
||||
is RedactQueuedTask -> RedactEventTaskInfo(
|
||||
redactionLocalEcho = task.redactionLocalEchoId,
|
||||
order = order
|
||||
)
|
||||
else -> null
|
||||
}
|
||||
return when (task) {
|
||||
is SendEventQueuedTask -> SendEventTaskInfo(
|
||||
localEchoId = task.event.eventId ?: "",
|
||||
encrypt = task.encrypt,
|
||||
order = order
|
||||
)
|
||||
is RedactQueuedTask -> RedactEventTaskInfo(
|
||||
redactionLocalEcho = task.redactionLocalEchoId,
|
||||
order = order
|
||||
)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
@ -90,7 +90,7 @@ internal class QueueMemento @Inject constructor(context: Context,
|
||||
?.forEach { info ->
|
||||
try {
|
||||
when (info) {
|
||||
is SendEventTaskInfo -> {
|
||||
is SendEventTaskInfo -> {
|
||||
localEchoRepository.getUpToDateEcho(info.localEchoId)?.let {
|
||||
if (it.sendState.isSending() && it.eventId != null && it.roomId != null) {
|
||||
localEchoRepository.updateSendState(it.eventId, it.roomId, SendState.UNSENT)
|
||||
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2021 The Matrix.org Foundation C.I.C
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.matrix.android.sdk.internal.session.thirdparty
|
||||
|
||||
import org.matrix.android.sdk.api.session.room.model.thirdparty.ThirdPartyProtocol
|
||||
import org.matrix.android.sdk.api.session.thirdparty.ThirdPartyService
|
||||
import org.matrix.android.sdk.api.session.thirdparty.model.ThirdPartyUser
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class DefaultThirdPartyService @Inject constructor(private val getThirdPartyProtocolTask: GetThirdPartyProtocolsTask,
|
||||
private val getThirdPartyUserTask: GetThirdPartyUserTask)
|
||||
: ThirdPartyService {
|
||||
|
||||
override suspend fun getThirdPartyProtocols(): Map<String, ThirdPartyProtocol> {
|
||||
return getThirdPartyProtocolTask.execute(Unit)
|
||||
}
|
||||
|
||||
override suspend fun getThirdPartyUser(protocol: String, fields: Map<String, String>): List<ThirdPartyUser> {
|
||||
val taskParams = GetThirdPartyUserTask.Params(
|
||||
protocol = protocol,
|
||||
fields = fields
|
||||
)
|
||||
return getThirdPartyUserTask.execute(taskParams)
|
||||
}
|
||||
}
|
@ -14,25 +14,24 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.matrix.android.sdk.internal.session.room.directory
|
||||
package org.matrix.android.sdk.internal.session.thirdparty
|
||||
|
||||
import org.matrix.android.sdk.api.session.room.model.thirdparty.ThirdPartyProtocol
|
||||
import org.matrix.android.sdk.internal.network.GlobalErrorReceiver
|
||||
import org.matrix.android.sdk.internal.network.executeRequest
|
||||
import org.matrix.android.sdk.internal.session.room.RoomAPI
|
||||
import org.matrix.android.sdk.internal.task.Task
|
||||
import javax.inject.Inject
|
||||
|
||||
internal interface GetThirdPartyProtocolsTask : Task<Unit, Map<String, ThirdPartyProtocol>>
|
||||
|
||||
internal class DefaultGetThirdPartyProtocolsTask @Inject constructor(
|
||||
private val roomAPI: RoomAPI,
|
||||
private val thirdPartyAPI: ThirdPartyAPI,
|
||||
private val globalErrorReceiver: GlobalErrorReceiver
|
||||
) : GetThirdPartyProtocolsTask {
|
||||
|
||||
override suspend fun execute(params: Unit): Map<String, ThirdPartyProtocol> {
|
||||
return executeRequest(globalErrorReceiver) {
|
||||
apiCall = roomAPI.thirdPartyProtocols()
|
||||
apiCall = thirdPartyAPI.thirdPartyProtocols()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.matrix.android.sdk.internal.session.thirdparty
|
||||
|
||||
import org.matrix.android.sdk.api.session.thirdparty.model.ThirdPartyUser
|
||||
import org.matrix.android.sdk.internal.network.GlobalErrorReceiver
|
||||
import org.matrix.android.sdk.internal.network.executeRequest
|
||||
import org.matrix.android.sdk.internal.task.Task
|
||||
import javax.inject.Inject
|
||||
|
||||
internal interface GetThirdPartyUserTask : Task<GetThirdPartyUserTask.Params, List<ThirdPartyUser>> {
|
||||
|
||||
data class Params(
|
||||
val protocol: String,
|
||||
val fields: Map<String, String> = emptyMap()
|
||||
)
|
||||
}
|
||||
|
||||
internal class DefaultGetThirdPartyUserTask @Inject constructor(
|
||||
private val thirdPartyAPI: ThirdPartyAPI,
|
||||
private val globalErrorReceiver: GlobalErrorReceiver
|
||||
) : GetThirdPartyUserTask {
|
||||
|
||||
override suspend fun execute(params: GetThirdPartyUserTask.Params): List<ThirdPartyUser> {
|
||||
return executeRequest(globalErrorReceiver) {
|
||||
apiCall = thirdPartyAPI.getThirdPartyUser(params.protocol, params.fields)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.matrix.android.sdk.internal.session.thirdparty
|
||||
|
||||
import org.matrix.android.sdk.api.session.room.model.thirdparty.ThirdPartyProtocol
|
||||
import org.matrix.android.sdk.api.session.thirdparty.model.ThirdPartyUser
|
||||
import org.matrix.android.sdk.internal.network.NetworkConstants
|
||||
import retrofit2.Call
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.Path
|
||||
import retrofit2.http.QueryMap
|
||||
|
||||
internal interface ThirdPartyAPI {
|
||||
|
||||
/**
|
||||
* Get the third party server protocols.
|
||||
*
|
||||
* Ref: https://matrix.org/docs/spec/client_server/r0.6.1.html#get-matrix-client-r0-thirdparty-protocols
|
||||
*/
|
||||
@GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "thirdparty/protocols")
|
||||
fun thirdPartyProtocols(): Call<Map<String, ThirdPartyProtocol>>
|
||||
|
||||
/**
|
||||
* Retrieve a Matrix User ID linked to a user on the third party service, given a set of user parameters.
|
||||
*
|
||||
* Ref: https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-thirdparty-user-protocol
|
||||
*/
|
||||
@GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "thirdparty/protocols/user/{protocol}")
|
||||
fun getThirdPartyUser(@Path("protocol") protocol: String, @QueryMap params: Map<String, String>?): Call<List<ThirdPartyUser>>
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.matrix.android.sdk.internal.session.thirdparty
|
||||
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import org.matrix.android.sdk.api.session.thirdparty.ThirdPartyService
|
||||
import org.matrix.android.sdk.internal.session.SessionScope
|
||||
import retrofit2.Retrofit
|
||||
|
||||
@Module
|
||||
internal abstract class ThirdPartyModule {
|
||||
|
||||
@Module
|
||||
companion object {
|
||||
@Provides
|
||||
@JvmStatic
|
||||
@SessionScope
|
||||
fun providesThirdPartyAPI(retrofit: Retrofit): ThirdPartyAPI {
|
||||
return retrofit.create(ThirdPartyAPI::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
@Binds
|
||||
abstract fun bindThirdPartyService(service: DefaultThirdPartyService): ThirdPartyService
|
||||
|
||||
@Binds
|
||||
abstract fun bindGetThirdPartyProtocolsTask(task: DefaultGetThirdPartyProtocolsTask): GetThirdPartyProtocolsTask
|
||||
|
||||
@Binds
|
||||
abstract fun bindGetThirdPartyUserTask(task: DefaultGetThirdPartyUserTask): GetThirdPartyUserTask
|
||||
}
|
@ -50,6 +50,10 @@ internal class DefaultWidgetService @Inject constructor(private val widgetManage
|
||||
return widgetManager.getRoomWidgets(roomId, widgetId, widgetTypes, excludedTypes)
|
||||
}
|
||||
|
||||
override fun getWidgetComputedUrl(widget: Widget, isLightTheme: Boolean): String? {
|
||||
return widgetManager.getWidgetComputedUrl(widget, isLightTheme)
|
||||
}
|
||||
|
||||
override fun getRoomWidgetsLive(
|
||||
roomId: String,
|
||||
widgetId: QueryStringValue,
|
||||
|
@ -104,6 +104,10 @@ internal class WidgetManager @Inject constructor(private val integrationManager:
|
||||
return widgetEvents.mapEventsToWidgets(widgetTypes, excludedTypes)
|
||||
}
|
||||
|
||||
fun getWidgetComputedUrl(widget: Widget, isLightTheme: Boolean): String? {
|
||||
return widgetFactory.computeURL(widget, isLightTheme)
|
||||
}
|
||||
|
||||
private fun List<Event>.mapEventsToWidgets(widgetTypes: Set<String>? = null,
|
||||
excludedTypes: Set<String>? = null): List<Widget> {
|
||||
val widgetEvents = this
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.session.widgets.helper
|
||||
|
||||
import org.matrix.android.sdk.api.session.content.ContentUrlResolver
|
||||
import org.matrix.android.sdk.api.session.events.model.Event
|
||||
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||
import org.matrix.android.sdk.api.session.room.sender.SenderInfo
|
||||
@ -31,6 +32,7 @@ import javax.inject.Inject
|
||||
|
||||
internal class WidgetFactory @Inject constructor(private val userDataSource: UserDataSource,
|
||||
private val realmSessionProvider: RealmSessionProvider,
|
||||
private val urlResolver: ContentUrlResolver,
|
||||
@UserId private val userId: String) {
|
||||
|
||||
fun create(widgetEvent: Event): Widget? {
|
||||
@ -53,30 +55,29 @@ internal class WidgetFactory @Inject constructor(private val userDataSource: Use
|
||||
}
|
||||
}
|
||||
val isAddedByMe = widgetEvent.senderId == userId
|
||||
val computedUrl = widgetContent.computeURL(widgetEvent.roomId, widgetId)
|
||||
return Widget(
|
||||
widgetContent = widgetContent,
|
||||
event = widgetEvent,
|
||||
widgetId = widgetId,
|
||||
senderInfo = senderInfo,
|
||||
isAddedByMe = isAddedByMe,
|
||||
computedUrl = computedUrl,
|
||||
type = WidgetType.fromString(type)
|
||||
)
|
||||
}
|
||||
|
||||
// Ref: https://github.com/matrix-org/matrix-widget-api/blob/master/src/templating/url-template.ts#L29-L33
|
||||
private fun WidgetContent.computeURL(roomId: String?, widgetId: String): String? {
|
||||
var computedUrl = url ?: return null
|
||||
fun computeURL(widget: Widget, isLightTheme: Boolean): String? {
|
||||
var computedUrl = widget.widgetContent.url ?: return null
|
||||
val myUser = userDataSource.getUser(userId)
|
||||
|
||||
val keyValue = data.mapKeys { "\$${it.key}" }.toMutableMap()
|
||||
val keyValue = widget.widgetContent.data.mapKeys { "\$${it.key}" }.toMutableMap()
|
||||
|
||||
keyValue[WIDGET_PATTERN_MATRIX_USER_ID] = userId
|
||||
keyValue[WIDGET_PATTERN_MATRIX_DISPLAY_NAME] = myUser?.getBestName() ?: userId
|
||||
keyValue[WIDGET_PATTERN_MATRIX_AVATAR_URL] = myUser?.avatarUrl ?: ""
|
||||
keyValue[WIDGET_PATTERN_MATRIX_WIDGET_ID] = widgetId
|
||||
keyValue[WIDGET_PATTERN_MATRIX_ROOM_ID] = roomId ?: ""
|
||||
keyValue[WIDGET_PATTERN_MATRIX_AVATAR_URL] = urlResolver.resolveFullSize(myUser?.avatarUrl) ?: ""
|
||||
keyValue[WIDGET_PATTERN_MATRIX_WIDGET_ID] = widget.widgetId
|
||||
keyValue[WIDGET_PATTERN_MATRIX_ROOM_ID] = widget.event.roomId ?: ""
|
||||
keyValue[WIDGET_PATTERN_THEME] = getTheme(isLightTheme)
|
||||
|
||||
for ((key, value) in keyValue) {
|
||||
computedUrl = computedUrl.replace(key, URLEncoder.encode(value.toString(), "utf-8"))
|
||||
@ -84,6 +85,10 @@ internal class WidgetFactory @Inject constructor(private val userDataSource: Use
|
||||
return computedUrl
|
||||
}
|
||||
|
||||
private fun getTheme(isLightTheme: Boolean): String {
|
||||
return if (isLightTheme) "light" else "dark"
|
||||
}
|
||||
|
||||
companion object {
|
||||
// Value to be replaced in URLS
|
||||
const val WIDGET_PATTERN_MATRIX_USER_ID = "\$matrix_user_id"
|
||||
@ -91,5 +96,6 @@ internal class WidgetFactory @Inject constructor(private val userDataSource: Use
|
||||
const val WIDGET_PATTERN_MATRIX_AVATAR_URL = "\$matrix_avatar_url"
|
||||
const val WIDGET_PATTERN_MATRIX_WIDGET_ID = "\$matrix_widget_id"
|
||||
const val WIDGET_PATTERN_MATRIX_ROOM_ID = "\$matrix_room_id"
|
||||
const val WIDGET_PATTERN_THEME = "\$theme"
|
||||
}
|
||||
}
|
||||
|
@ -80,4 +80,22 @@
|
||||
<string name="notice_room_invite_no_invitee_by_you">O teu convite</string>
|
||||
<string name="summary_you_sent_sticker">Enviaches un adhesivo.</string>
|
||||
<string name="summary_you_sent_image">Enviaches unha imaxe.</string>
|
||||
<string name="notice_room_server_acl_set_ip_literals_not_allowed">• Servidores con literais IP están vetados.</string>
|
||||
<string name="notice_room_server_acl_set_ip_literals_allowed">• Servidores con IP literais están permitidos.</string>
|
||||
<string name="notice_room_server_acl_set_banned">• Servidores con %s están vetados.</string>
|
||||
<string name="notice_room_server_acl_set_allowed">• Servidores con %s están permitidos.</string>
|
||||
<string name="notice_room_server_acl_set_title_by_you">Estableceches os ACLs do servidor para esta sala.</string>
|
||||
<string name="notice_room_server_acl_set_title">%s estableceu os ACLs do servidor para esta sala.</string>
|
||||
<string name="notice_direct_room_update">%s actualizou aquí.</string>
|
||||
<string name="notice_direct_room_update_by_you">Actualizaches aquí.</string>
|
||||
<string name="notice_room_update_by_you">Actualizaches esta sala.</string>
|
||||
<string name="notice_room_update">%s actualizou esta sala.</string>
|
||||
<string name="notice_end_to_end_by_you">Activaches o cifrado extremo-a-extremo (%1$s)</string>
|
||||
<string name="notice_made_future_direct_room_visibility_by_you">Fixeches visibles as mensaxes futuras para %1$s</string>
|
||||
<string name="notice_made_future_direct_room_visibility">%1$s fixo visibles as mensaxes futuras para %2$s</string>
|
||||
<string name="notice_made_future_room_visibility_by_you">Fixeches visible no futuro o historial da sala para %1$s</string>
|
||||
<string name="notice_ended_call_by_you">Remataches a chamada.</string>
|
||||
<string name="notice_answered_call_by_you">Respondeches á chamada.</string>
|
||||
<string name="notice_call_candidates_by_you">Enviaches datos para configurar a chamada.</string>
|
||||
<string name="notice_call_candidates">%s enviou datos para configurar a chamada.</string>
|
||||
</resources>
|
@ -2,46 +2,46 @@
|
||||
<resources>
|
||||
<string name="summary_message">%1$s: %2$s</string>
|
||||
<string name="summary_user_sent_image">%1$s nosūtīja attēlu.</string>
|
||||
<string name="notice_room_invite_no_invitee">%s\'s uzaicinājums</string>
|
||||
<string name="notice_room_invite_no_invitee">Uzaicinājums no %s</string>
|
||||
<string name="notice_room_invite">%1$s uzaicināja %2$s</string>
|
||||
<string name="notice_room_invite_you">%1$s uzaicināja tevi</string>
|
||||
<string name="notice_room_invite_you">%1$s uzaicināja jūs</string>
|
||||
<string name="notice_room_join">%1$s pievienojās</string>
|
||||
<string name="notice_room_leave">%1$s atstāja</string>
|
||||
<string name="notice_room_leave">%1$s pameta istabu</string>
|
||||
<string name="notice_room_reject">%1$s noraidīja uzaicinājumu</string>
|
||||
<string name="notice_room_kick">%1$s \"izspēra\" ārā %2$s</string>
|
||||
<string name="notice_room_unban">%1$s atbanoja (atcēla pieejas liegumu) %2$s</string>
|
||||
<string name="notice_room_ban">%1$s liedza pieeju (banoja) %2$s</string>
|
||||
<string name="notice_room_kick">%1$s padzina %2$s</string>
|
||||
<string name="notice_room_unban">%1$s atcēla pieejas liegumu %2$s</string>
|
||||
<string name="notice_room_ban">%1$s liedza pieeju %2$s</string>
|
||||
<string name="notice_room_withdraw">%1$s atsauca %2$s uzaicinājumu</string>
|
||||
<string name="notice_avatar_url_changed">%1$s nomainīja profila attēlu</string>
|
||||
<string name="notice_display_name_set">%1$s uzstādīja redzamo vārdu uz %2$s</string>
|
||||
<string name="notice_display_name_changed_from">%1$s nomainīja redzamo vārdu no %2$s uz %3$s</string>
|
||||
<string name="notice_display_name_removed">%1$s dzēsa savu redzamo vārdu (%2$s)</string>
|
||||
<string name="notice_room_topic_changed">%1$s nomainīja tēmas nosaukumu uz: %2$s</string>
|
||||
<string name="notice_room_name_changed">%1$s nomainīja istabas nosaukumu uz: %2$s</string>
|
||||
<string name="notice_avatar_url_changed">%1$s nomainīja avataru</string>
|
||||
<string name="notice_display_name_set">%1$s uzstādīja parādāmo vārdu uz %2$s</string>
|
||||
<string name="notice_display_name_changed_from">%1$s nomainīja parādāmo vārdu no %2$s uz %3$s</string>
|
||||
<string name="notice_display_name_removed">%1$s dzēsa savu parādāmo vārdu (iepriekš %2$s)</string>
|
||||
<string name="notice_room_topic_changed">%1$s nomainīja tematu uz %2$s</string>
|
||||
<string name="notice_room_name_changed">%1$s nomainīja istabas nosaukumu uz %2$s</string>
|
||||
<string name="notice_placed_video_call">%s veica video zvanu.</string>
|
||||
<string name="notice_placed_voice_call">%s veica audio zvanu.</string>
|
||||
<string name="notice_answered_call">%s atbildēja zvanam.</string>
|
||||
<string name="notice_answered_call">%s atbildēja uz zvanu.</string>
|
||||
<string name="notice_ended_call">%s beidza zvanu.</string>
|
||||
<string name="notice_made_future_room_visibility">%1$s padarīja istabas nākamo ziņu vēsturi redzamu %2$s</string>
|
||||
<string name="notice_made_future_room_visibility">%1$s padarīja istabas turpmāko ziņu vēsturi redzamu %2$s</string>
|
||||
<string name="notice_room_visibility_invited">visi istabas biedri no brīža, kad tika uzaicināti.</string>
|
||||
<string name="notice_room_visibility_joined">visi istabas biedri no brīža, kad tika pievienojušies.</string>
|
||||
<string name="notice_room_visibility_shared">visi istabas biedri.</string>
|
||||
<string name="notice_room_visibility_world_readable">ikviens.</string>
|
||||
<string name="notice_room_visibility_unknown">nezināms (%s).</string>
|
||||
<string name="notice_end_to_end">%1$s ieslēdza ierīce-ierīce šifrēšanu (%2$s)</string>
|
||||
<string name="notice_requested_voip_conference">%1$s vēlas VoIP konferenci</string>
|
||||
<string name="notice_voip_started">VoIP konference sākusies</string>
|
||||
<string name="notice_voip_finished">VoIP konference ir beigusies</string>
|
||||
<string name="notice_avatar_changed_too">(arī profila attēls mainījās)</string>
|
||||
<string name="notice_end_to_end">%1$s ieslēdza pilnīgu šifrēšanu (%2$s)</string>
|
||||
<string name="notice_requested_voip_conference">%1$s pieprasīja VoIP konferenci</string>
|
||||
<string name="notice_voip_started">VoIP konference sākās</string>
|
||||
<string name="notice_voip_finished">VoIP konference beidzās</string>
|
||||
<string name="notice_avatar_changed_too">(arī avatars tika nomainīts)</string>
|
||||
<string name="notice_room_name_removed">%1$s dzēsa istabas nosaukumu</string>
|
||||
<string name="notice_room_topic_removed">%1$s dzēsa istabas tēmas nosaukumu</string>
|
||||
<string name="notice_profile_change_redacted">%1$s atjaunoja profila informāciju %2$s</string>
|
||||
<string name="notice_room_third_party_invite">%1$s nosūtīja uzaicinājumu %2$s pievienoties istabai</string>
|
||||
<string name="notice_room_third_party_registered_invite">%1$s apstiprināja uzaicinājumu priekš %2$s</string>
|
||||
<string name="notice_crypto_unable_to_decrypt">** Nav iespējams atkodēt: %s **</string>
|
||||
<string name="notice_crypto_error_unkwown_inbound_session_id">Sūtītāja ierīce mums nenosūtīja atslēgas priekš šīs ziņas.</string>
|
||||
<string name="notice_room_topic_removed">%1$s izdzēsa istabas tematu</string>
|
||||
<string name="notice_profile_change_redacted">%1$s atjaunoja savu profilu %2$s</string>
|
||||
<string name="notice_room_third_party_invite">%1$s nosūtīja %2$s uzaicinājumu pievienoties istabai</string>
|
||||
<string name="notice_room_third_party_registered_invite">%1$s pieņēma uzaicinājumu %2$s</string>
|
||||
<string name="notice_crypto_unable_to_decrypt">** Neizdodas atšifrēt: %s **</string>
|
||||
<string name="notice_crypto_error_unkwown_inbound_session_id">Sūtītāja ierīce mums nav nenosūtījusi atslēgas priekš šīs ziņas.</string>
|
||||
<string name="could_not_redact">Nevarēja rediģēt</string>
|
||||
<string name="unable_to_send_message">Nav iespējams nosūtīt ziņu</string>
|
||||
<string name="unable_to_send_message">Neizdodas nosūtīt ziņu</string>
|
||||
<string name="message_failed_to_upload">Neizdevās augšuplādēt attēlu</string>
|
||||
<string name="network_error">Tīkla kļūda</string>
|
||||
<string name="matrix_error">Matrix kļūda</string>
|
||||
@ -58,27 +58,188 @@
|
||||
<item quantity="one">%1$s un %2$d citi</item>
|
||||
<item quantity="other">%1$s un %2$d citu</item>
|
||||
</plurals>
|
||||
<string name="notice_display_name_changed_from_by_you">Tu nomainīji savu attēlojamo vārdu no %1$s uz %2$s</string>
|
||||
<string name="notice_display_name_set_by_you">Tu nomainījis savu attēlojamo vārdu uz %1$s</string>
|
||||
<string name="notice_avatar_url_changed_by_you">Tu nomainīji savu avataru</string>
|
||||
<string name="notice_room_withdraw_by_you">Tu atsauci %1$s uzaicinājumu</string>
|
||||
<string name="notice_room_ban_by_you">Tu nobanoji %1$s</string>
|
||||
<string name="notice_room_unban_by_you">Tu atbanoji %1$s</string>
|
||||
<string name="notice_room_kick_by_you">Tu izspēri %1$s</string>
|
||||
<string name="notice_room_reject_by_you">Tu noraidīji uzaicinājumu</string>
|
||||
<string name="notice_direct_room_leave_by_you">Tu pameti telpu</string>
|
||||
<string name="notice_direct_room_leave">%1$s atstāja telpu</string>
|
||||
<string name="notice_room_leave_by_you">Tu atstāji telpu</string>
|
||||
<string name="notice_direct_room_join_by_you">Tu pievienojies</string>
|
||||
<string name="notice_direct_room_join">%1$s pievienojās telpai</string>
|
||||
<string name="notice_room_join_by_you">Tu pievienojies telpai</string>
|
||||
<string name="notice_room_invite_by_you">Tu uzaicināji %1$s</string>
|
||||
<string name="notice_direct_room_created_by_you">Tu izveidoji apspriedi (diskusiju)</string>
|
||||
<string name="notice_direct_room_created">%1$s izveidoja apspriedi (diskusiju)</string>
|
||||
<string name="notice_room_created_by_you">Tu izveidoji istabu</string>
|
||||
<string name="notice_room_created">%1$s izveidoja telpu</string>
|
||||
<string name="notice_room_invite_no_invitee_by_you">Tavs uzaicinājums</string>
|
||||
<string name="summary_you_sent_sticker">Tu nosūtīji uzlīmi/lipekli.</string>
|
||||
<string name="summary_user_sent_sticker">%1$s nosūtīja uzlīmi/lipekli.</string>
|
||||
<string name="summary_you_sent_image">Tu nosūtīji attēlu.</string>
|
||||
<string name="notice_display_name_changed_from_by_you">Jūs nomainījāt savu parādāmo vārdu no %1$s uz %2$s</string>
|
||||
<string name="notice_display_name_set_by_you">Jūs nomainījāt savu parādāmo vārdu uz %1$s</string>
|
||||
<string name="notice_avatar_url_changed_by_you">Jūs nomainījāt savu avataru</string>
|
||||
<string name="notice_room_withdraw_by_you">Jūs atsaucāt %1$s uzaicinājumu</string>
|
||||
<string name="notice_room_ban_by_you">Jūs liedzāt pieeju %1$s</string>
|
||||
<string name="notice_room_unban_by_you">Jūs atcēlāt pieejas liegumu %1$s</string>
|
||||
<string name="notice_room_kick_by_you">Jūs padzināt %1$s</string>
|
||||
<string name="notice_room_reject_by_you">Jūs noraidījāt uzaicinājumu</string>
|
||||
<string name="notice_direct_room_leave_by_you">Jūs pametāt istabu</string>
|
||||
<string name="notice_direct_room_leave">%1$s pameta istabu</string>
|
||||
<string name="notice_room_leave_by_you">Jūs pametāt istabu</string>
|
||||
<string name="notice_direct_room_join_by_you">Jūs pievienojāties</string>
|
||||
<string name="notice_direct_room_join">%1$s pievienojās istabai</string>
|
||||
<string name="notice_room_join_by_you">Jūs pievienojāties istabai</string>
|
||||
<string name="notice_room_invite_by_you">Jūs uzaicinājāt %1$s</string>
|
||||
<string name="notice_direct_room_created_by_you">Jūs izveidojāt diskusiju</string>
|
||||
<string name="notice_direct_room_created">%1$s izveidoja diskusiju</string>
|
||||
<string name="notice_room_created_by_you">Jūs izveidojāt istabu</string>
|
||||
<string name="notice_room_created">%1$s izveidoja istabu</string>
|
||||
<string name="notice_room_invite_no_invitee_by_you">Jūsu uzaicinājums</string>
|
||||
<string name="summary_you_sent_sticker">Jūs nosūtījāt uzlīmi.</string>
|
||||
<string name="summary_user_sent_sticker">%1$s nosūtīja uzlīmi.</string>
|
||||
<string name="summary_you_sent_image">Jūs nosūtījāt attēlu.</string>
|
||||
<string name="key_verification_request_fallback_message">%s pieprasa verificēt jūsu atslēgu, taču jūsu klients neatbalsta tērzēšanas atslēgas verifikāciju. Lai verificētu atslēgas, jums būs jāizmanto atslēgu verifikācija novecojušā veidā.</string>
|
||||
<string name="notice_end_to_end_unknown_algorithm_by_you">Jūs ieslēdzāt pilnīgu šifrēšanu (neatpazīts algoritms %1$s).</string>
|
||||
<string name="notice_end_to_end_unknown_algorithm">%1$s ieslēdza pilnīgu šifrēšanu (neatpazīts algoritms %2$s).</string>
|
||||
<string name="notice_end_to_end_ok_by_you">Jūs ieslēdzāt pilnīgu šifrēšanu.</string>
|
||||
<string name="notice_end_to_end_ok">%1$s ieslēdza pilnīgu šifrēšanu.</string>
|
||||
<string name="notice_direct_room_guest_access_forbidden_by_you">Jūs esat novērsis iespēju viesiem pievienoties istabai.</string>
|
||||
<string name="notice_direct_room_guest_access_forbidden">%1$s ir novērsis iespēju viesiem pievienoties istabai.</string>
|
||||
<string name="notice_room_guest_access_forbidden_by_you">Jūs esat novērsis iespēju viesiem pievienoties istabai.</string>
|
||||
<string name="notice_room_guest_access_forbidden">%1$s ir novērsis iespēju viesiem pievienoties istabai.</string>
|
||||
<string name="notice_direct_room_guest_access_can_join_by_you">Jūs esat atļāvis viesiem pievienoties istabai.</string>
|
||||
<string name="notice_direct_room_guest_access_can_join">%1$s ir atļāvis viesiem pievienoties istabai.</string>
|
||||
<string name="notice_room_guest_access_can_join_by_you">Jūs esat atļāvis viesiem pievienoties istabai.</string>
|
||||
<string name="notice_room_guest_access_can_join">%1$s ir atļāvis viesiem pievienoties istabai.</string>
|
||||
<string name="notice_room_canonical_alias_no_change_by_you">Jūs nomainījāt adreses šai istabai.</string>
|
||||
<string name="notice_room_canonical_alias_no_change">%1$s nomainīja adreses šai istabai.</string>
|
||||
<string name="notice_room_canonical_alias_main_and_alternative_changed_by_you">Jūs nomainījāt galveno un alternatīvās adreses šai istabai.</string>
|
||||
<string name="notice_room_canonical_alias_main_and_alternative_changed">%1$s nomainīja galveno un alternatīvās adreses šai istabai.</string>
|
||||
<string name="notice_room_canonical_alias_alternative_changed_by_you">Jūs nomainījāt alternatīvās adreses šai istabai.</string>
|
||||
<string name="notice_room_canonical_alias_alternative_changed">%1$s nomainīja alternatīvās adreses šai istabai.</string>
|
||||
<plurals name="notice_room_canonical_alias_alternative_removed_by_you">
|
||||
<item quantity="zero">Jūs izdzēsāt šīs istabas alternatīvo adresi %1$s.</item>
|
||||
<item quantity="one">Jūs izdzēsāt šīs istabas alternatīvās adreses %1$s.</item>
|
||||
<item quantity="other">Jūs izdzēsāt šīs istabas alternatīvās adreses %1$s.</item>
|
||||
</plurals>
|
||||
<plurals name="notice_room_canonical_alias_alternative_removed">
|
||||
<item quantity="zero">%1$s izdzēsa šīs istabas alternatīvo adresi %2$s.</item>
|
||||
<item quantity="one">%1$s izdzēsa šīs istabas alternatīvās adreses %2$s.</item>
|
||||
<item quantity="other">%1$s izdzēsa šīs istabas alternatīvās adreses %2$s.</item>
|
||||
</plurals>
|
||||
<plurals name="notice_room_canonical_alias_alternative_added_by_you">
|
||||
<item quantity="zero">Jūs pievienojāt šīs istabas alternatīvo adresi %1$s.</item>
|
||||
<item quantity="one">Jūs pievienojāt šīs istabas alternatīvās adreses %1$s.</item>
|
||||
<item quantity="other">Jūs pievienojāt šīs istabas alternatīvās adreses %1$s.</item>
|
||||
</plurals>
|
||||
<plurals name="notice_room_canonical_alias_alternative_added">
|
||||
<item quantity="zero">%1$s pievienoja šīs istabas alternatīvo adresi %2$s.</item>
|
||||
<item quantity="one">%1$s pievienoja šīs istabas alternatīvās adreses %2$s.</item>
|
||||
<item quantity="other">%1$s pievienoja šīs istabas alternatīvās adreses %2$s.</item>
|
||||
</plurals>
|
||||
<string name="notice_room_canonical_alias_unset_by_you">Jūs izdzēsāt šis istabas galveno adresi.</string>
|
||||
<string name="notice_room_canonical_alias_unset">%1$s izdzēsa šis istabas galveno adresi.</string>
|
||||
<string name="notice_room_canonical_alias_set_by_you">Jūs iestatījāt %1$s kā šis istabas galveno adresi.</string>
|
||||
<string name="notice_room_canonical_alias_set">%1$s iestatīja %2$s kā šis istabas galveno adresi.</string>
|
||||
<string name="notice_room_aliases_added_and_removed_by_you">Jūs pievienojāt %1$s un izdzēsāt %2$s kā šīs istabas adreses.</string>
|
||||
<string name="notice_room_aliases_added_and_removed">%1$s pievienoja %2$s un izdzēsa %3$s kā šīs istabas adreses.</string>
|
||||
<plurals name="notice_room_aliases_removed_by_you">
|
||||
<item quantity="zero">Jūs izdzēsāt %1$s kā šīs istabas adresi.</item>
|
||||
<item quantity="one">Jūs izdzēsāt %1$s kā šīs istabas adreses.</item>
|
||||
<item quantity="other">Jūs izdzēsāt %1$s kā šīs istabas adreses.</item>
|
||||
</plurals>
|
||||
<plurals name="notice_room_aliases_removed">
|
||||
<item quantity="zero">%1$s izdzēsa %2$s kā šīs istabas adresi.</item>
|
||||
<item quantity="one">%1$s izdzēsa %2$s kā šīs istabas adreses.</item>
|
||||
<item quantity="other">%1$s izdzēsa %2$s kā šīs istabas adreses.</item>
|
||||
</plurals>
|
||||
<plurals name="notice_room_aliases_added_by_you">
|
||||
<item quantity="zero">Jūs pievienojāt %1$s kā šīs istabas adresi.</item>
|
||||
<item quantity="one">Jūs pievienojāt %1$s kā šīs istabas adreses.</item>
|
||||
<item quantity="other">Jūs pievienojāt %1$s kā šīs istabas adreses.</item>
|
||||
</plurals>
|
||||
<plurals name="notice_room_aliases_added">
|
||||
<item quantity="zero">%1$s pievienoja %2$s kā šīs istabas adresi.</item>
|
||||
<item quantity="one">%1$s pievienoja %2$s kā šis istabas adreses.</item>
|
||||
<item quantity="other">%1$s pievienoja %2$s kā šīs istabas adreses.</item>
|
||||
</plurals>
|
||||
<string name="notice_room_withdraw_with_reason_by_you">Jūs atsaucāt %1$s uzaicinājumu. Iemesls: %2$s</string>
|
||||
<string name="notice_room_withdraw_with_reason">%1$s atsauca uzaicinājumu %2$s. Iemesls: %3$s</string>
|
||||
<string name="notice_room_third_party_registered_invite_with_reason_by_you">Jūs pieņēmāt uzaicinājumu %1$s. Iemesls: %2$s</string>
|
||||
<string name="notice_room_third_party_registered_invite_with_reason">%1$s pieņēma uzaicinājumu %2$s. Iemesls: %3$s</string>
|
||||
<string name="notice_room_third_party_revoked_invite_with_reason_by_you">Jūs atsaucāt uzaicinājumu %1$s pievienoties istabai. Iemesls: %2$s</string>
|
||||
<string name="notice_room_third_party_revoked_invite_with_reason">%1$s atsauca uzaicinājumu %2$s pievienoties istabai. Iemesls: %3$s</string>
|
||||
<string name="notice_room_third_party_invite_with_reason_by_you">Jūs nosūtījāt uzaicinājumu %1$s pievienoties istabai. Iemesls: %2$s</string>
|
||||
<string name="notice_room_third_party_invite_with_reason">%1$s nosūtīja uzaicinājumu %2$s pievienoties istabai. Iemesls: %3$s</string>
|
||||
<string name="notice_room_ban_with_reason_by_you">Jūs liedzāt pieeju %1$s. Iemesls: %2$s</string>
|
||||
<string name="notice_room_ban_with_reason">%1$s liedza pieeju %2$s. Iemesls: %3$s</string>
|
||||
<string name="notice_room_unban_with_reason_by_you">Jūs atcēlāt pieejas liegumu %1$s. Iemesls: %2$s</string>
|
||||
<string name="notice_room_unban_with_reason">%1$s atcēla %2$s pieejas liegumu. Iemesls: %3$s</string>
|
||||
<string name="notice_room_kick_with_reason_by_you">Jūs padzināt %1$s. Iemesls: %2$s</string>
|
||||
<string name="notice_room_kick_with_reason">%1$s padzina %2$s. Iemesls: %3$s</string>
|
||||
<string name="notice_room_reject_with_reason_by_you">Jūs noraidījāt uzaicinājumu. Iemesls: %1$s</string>
|
||||
<string name="notice_room_reject_with_reason">%1$s noraidīja uzaicinājumu. Iemesls: %2$s</string>
|
||||
<string name="notice_direct_room_leave_with_reason_by_you">Jūs izgājāt. Iemesls: %1$s</string>
|
||||
<string name="notice_direct_room_leave_with_reason">%1$s izgāja. Iemels: %2$s</string>
|
||||
<string name="notice_room_leave_with_reason_by_you">Jūs pametāt istabu. Iemesls: %1$s</string>
|
||||
<string name="notice_room_leave_with_reason">%1$s pameta istabu. Iemesls: %2$s</string>
|
||||
<string name="notice_direct_room_join_with_reason_by_you">Jūs pievienojāties. Iemesls: %1$s</string>
|
||||
<string name="notice_direct_room_join_with_reason">%1$s pievienojās. Iemesls: %2$s</string>
|
||||
<string name="notice_room_join_with_reason_by_you">Jūs pievienojāties istabai. Iemesls: %1$s</string>
|
||||
<string name="notice_room_join_with_reason">%1$s pievienojās istabai. Iemesls: %2$s</string>
|
||||
<string name="notice_room_invite_you_with_reason">%1$s uzaicināja jūs. Iemesls: %2$s</string>
|
||||
<string name="notice_room_invite_with_reason_by_you">Jūs uzaicinājāt %1$s. Iemesls: %2$s</string>
|
||||
<string name="notice_room_invite_with_reason">%1$s uzaicināja %2$s. Iemesls: %3$s</string>
|
||||
<string name="notice_room_invite_no_invitee_with_reason_by_you">Jūsu uzaicinājums. Iemesls: %1$s</string>
|
||||
<string name="notice_room_invite_no_invitee_with_reason">%1$s uzaicinājums. Iemesls: %2$s</string>
|
||||
<string name="clear_timeline_send_queue">Notīrīt sūtīšanas rindu</string>
|
||||
<string name="event_status_sending_message">Sūta ziņu…</string>
|
||||
<string name="initial_sync_start_importing_account_data">Sākotnējā sinhronizācija:
|
||||
\nImportē konta datus</string>
|
||||
<string name="initial_sync_start_importing_account_groups">Sākotnējā sinhronizācija:
|
||||
\nImportē kopienas</string>
|
||||
<string name="initial_sync_start_importing_account_left_rooms">Sākotnējā sinhronizācija:
|
||||
\nImportē pamestās istabas</string>
|
||||
<string name="initial_sync_start_importing_account_invited_rooms">Sākotnējā sinhronizācija:
|
||||
\nImportē istabas, uz kurām uzaicināts</string>
|
||||
<string name="initial_sync_start_importing_account_joined_rooms">Sākotnējā sinhronizācija:
|
||||
\nImportē istabas, kurās ieiets</string>
|
||||
<string name="initial_sync_start_importing_account_rooms">Sākotnējā sinhronizācija:
|
||||
\nImportē istabas</string>
|
||||
<string name="initial_sync_start_importing_account_crypto">Sākotnējā sinhronizācija:
|
||||
\nImportē kriptogrāfiju</string>
|
||||
<string name="initial_sync_start_importing_account">Sākotnējā sinhronizācija:
|
||||
\nImportē kontu…</string>
|
||||
<string name="room_displayname_empty_room_was">Tukša istaba (bija %s)</string>
|
||||
<plurals name="room_displayname_four_and_more_members">
|
||||
<item quantity="zero">%1$s, %2$s, %3$s un %4$d citi</item>
|
||||
<item quantity="one">%1$s, %2$s, %3$s un %4$d cits</item>
|
||||
<item quantity="other">%1$s, %2$s, %3$s un %4$d citi</item>
|
||||
</plurals>
|
||||
<string name="room_displayname_4_members">%1$s, %2$s, %3$s un %4$s</string>
|
||||
<string name="room_displayname_3_members">%1$s, %2$s un %3$s</string>
|
||||
<string name="notice_power_level_diff">%1$s no %2$s uz %3$s</string>
|
||||
<string name="notice_power_level_changed">%1$s nomainīja %2$s pieejas līmeni.</string>
|
||||
<string name="notice_power_level_changed_by_you">Jūs nomainījāt %1$s pieejas līmeni.</string>
|
||||
<string name="power_level_custom_no_value">Pielāgots</string>
|
||||
<string name="power_level_custom">Pielāgots (%1$d)</string>
|
||||
<string name="power_level_default">Noklusējuma</string>
|
||||
<string name="power_level_moderator">Moderators</string>
|
||||
<string name="power_level_admin">Administrators</string>
|
||||
<string name="notice_room_third_party_registered_invite_by_you">Jūs pieņēmāt uzaicinājumu %1$s</string>
|
||||
<string name="notice_direct_room_third_party_revoked_invite_by_you">Jūs atsaucāt uzaicinājumu %1$s</string>
|
||||
<string name="notice_direct_room_third_party_revoked_invite">%1$s atsauca uzaicinājumu %2$s</string>
|
||||
<string name="notice_room_third_party_revoked_invite_by_you">Jūs atsaucāt uzaicinājumu %1$s pievienoties istabai</string>
|
||||
<string name="notice_room_third_party_revoked_invite">%1$s atsauca uzaicinājumu %2$s pievienoties istabai</string>
|
||||
<string name="notice_direct_room_third_party_invite_by_you">Jūs uzaicinājāt %1$s</string>
|
||||
<string name="notice_direct_room_third_party_invite">%1$s uzaicināja %2$s</string>
|
||||
<string name="notice_room_third_party_invite_by_you">Jūs nosūtījāt %1$s uzaicinājumu pievienoties istabai</string>
|
||||
<string name="notice_profile_change_redacted_by_you">Jūs atjaunojāt savu profilu %1$s</string>
|
||||
<string name="notice_event_redacted_by_with_reason">%1$s izdzēsa ziņu [iemesls: %2$s]</string>
|
||||
<string name="notice_event_redacted_with_reason">Ziņa izdzēsta [iemesls: %1$s]</string>
|
||||
<string name="notice_event_redacted_by">%1$s izdzēsa ziņu</string>
|
||||
<string name="notice_event_redacted">Ziņa izdzēsta</string>
|
||||
<string name="notice_room_avatar_removed_by_you">Jūs izdzēsāt istabas avataru</string>
|
||||
<string name="notice_room_avatar_removed">%1$s izdzēsa istabas avataru</string>
|
||||
<string name="notice_room_topic_removed_by_you">Jūs izdzēsāt istabas tematu</string>
|
||||
<string name="notice_room_name_removed_by_you">Jūs dzēsāt istabas nosaukumu</string>
|
||||
<string name="notice_requested_voip_conference_by_you">Jūs pieprasījāt VoIP konferenci</string>
|
||||
<string name="notice_end_to_end_by_you">Jūs ieslēdzāt pilnīgu šifrēšanu (%1$s)</string>
|
||||
<string name="notice_made_future_direct_room_visibility_by_you">Jūs padarījāt turpmākās ziņas redzamas %1$s</string>
|
||||
<string name="notice_made_future_direct_room_visibility">%1$s padarīja turpmākās ziņas redzamas %2$s</string>
|
||||
<string name="notice_made_future_room_visibility_by_you">Jūs padarījāt istabas turpmāko ziņu vēsturi redzamu %1$s</string>
|
||||
<string name="notice_ended_call_by_you">Jūs beidzāt zvanu.</string>
|
||||
<string name="notice_answered_call_by_you">Jūs atbildējāt uz zvanu.</string>
|
||||
<string name="notice_call_candidates_by_you">Jūs nosūtījāt datus zvana uzsākšanai.</string>
|
||||
<string name="notice_call_candidates">%s nosūtīja datus zvana uzsākšanai.</string>
|
||||
<string name="notice_placed_voice_call_by_you">Jūs veicāt balss zvanu.</string>
|
||||
<string name="notice_placed_video_call_by_you">Jūs veicāt video zvanu.</string>
|
||||
<string name="notice_room_name_changed_by_you">Jūs nomainījāt istabas nosaukumu uz %1$s</string>
|
||||
<string name="notice_room_avatar_changed_by_you">Jūs nomainījāt istabas avataru</string>
|
||||
<string name="notice_room_avatar_changed">%1$s nomainīja istabas avataru</string>
|
||||
<string name="notice_room_topic_changed_by_you">Jūs nomainījāt tematu uz %1$s</string>
|
||||
<string name="notice_display_name_removed_by_you">Jūs dzēsāt savu parādāmo vārdu (iepriekš %1$s)</string>
|
||||
</resources>
|
@ -161,7 +161,7 @@ Formatter\.formatShortFileSize===1
|
||||
# android\.text\.TextUtils
|
||||
|
||||
### This is not a rule, but a warning: the number of "enum class" has changed. For Json classes, it is mandatory that they have `@JsonClass(generateAdapter = false)`. If the enum is not used as a Json class, change the value in file forbidden_strings_in_code.txt
|
||||
enum class===85
|
||||
enum class===88
|
||||
|
||||
### Do not import temporary legacy classes
|
||||
import org.matrix.android.sdk.internal.legacy.riot===3
|
||||
|
@ -25,8 +25,8 @@ cd jitsi-meet
|
||||
# This is commit after version 2.2.2, which does not compile
|
||||
# git checkout 5a934c071a5cbe64de275a25d0ed62d8193cdd03
|
||||
|
||||
# Version android-sdk-2.9.3, commit abcbbbea12e3ef88012b14723bb8cd42dbefc988
|
||||
git checkout android-sdk-2.9.3
|
||||
# Version android-sdk-3.1.0, commit 7a64bf006ea027b77564d8847570e1ac46ff0ec0
|
||||
git checkout android-sdk-3.1.0
|
||||
|
||||
echo
|
||||
echo "##################################################"
|
||||
|
@ -114,6 +114,9 @@ android {
|
||||
targetSdkVersion 30
|
||||
multiDexEnabled true
|
||||
|
||||
renderscriptTargetApi 24
|
||||
renderscriptSupportModeEnabled true
|
||||
|
||||
// `develop` branch will have version code from timestamp, to ensure each build from CI has a incremented versionCode.
|
||||
// Other branches (master, features, etc.) will have version code based on application version.
|
||||
versionCode project.getVersionCode()
|
||||
@ -232,7 +235,7 @@ android {
|
||||
productFlavors {
|
||||
gplay {
|
||||
dimension "store"
|
||||
|
||||
isDefault = true
|
||||
versionName "${versionMajor}.${versionMinor}.${versionPatch}${getGplayVersionSuffix()}"
|
||||
|
||||
resValue "bool", "isGplay", "true"
|
||||
@ -319,6 +322,7 @@ dependencies {
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
|
||||
implementation "androidx.sharetarget:sharetarget:1.0.0"
|
||||
implementation 'androidx.core:core-ktx:1.3.2'
|
||||
implementation "androidx.media:media:1.2.1"
|
||||
|
||||
implementation "org.threeten:threetenbp:1.4.0:no-tzdb"
|
||||
implementation "com.gabrielittner.threetenbp:lazythreetenbp:0.7.0"
|
||||
@ -373,6 +377,7 @@ dependencies {
|
||||
implementation 'me.saket:better-link-movement-method:2.2.0'
|
||||
implementation 'com.google.android:flexbox:1.1.1'
|
||||
implementation "androidx.autofill:autofill:$autofill_version"
|
||||
implementation 'jp.wasabeef:glide-transformations:4.3.0'
|
||||
implementation 'com.github.vector-im:PFLockScreen-Android:1.0.0-beta12'
|
||||
|
||||
// Custom Tab
|
||||
@ -430,7 +435,10 @@ dependencies {
|
||||
// WebRTC
|
||||
// org.webrtc:google-webrtc is for development purposes only
|
||||
// implementation 'org.webrtc:google-webrtc:1.0.+'
|
||||
implementation('org.jitsi.react:jitsi-meet-sdk:2.9.3') { transitive = true }
|
||||
implementation('com.facebook.react:react-native-webrtc:1.87.3-jitsi-6624067@aar')
|
||||
|
||||
// Jitsi
|
||||
implementation('org.jitsi.react:jitsi-meet-sdk:3.1.0')
|
||||
|
||||
// QR-code
|
||||
// Stick to 3.3.3 because of https://github.com/zxing/zxing/issues/1170
|
||||
@ -441,6 +449,8 @@ dependencies {
|
||||
implementation 'com.vanniktech:emoji-material:0.7.0'
|
||||
implementation 'com.vanniktech:emoji-google:0.7.0'
|
||||
|
||||
implementation 'im.dlg:android-dialer:1.2.5'
|
||||
|
||||
// TESTS
|
||||
testImplementation 'junit:junit:4.13'
|
||||
testImplementation "org.amshove.kluent:kluent-android:$kluent_version"
|
||||
|
@ -277,8 +277,23 @@ class UiAllScreensSanityTest {
|
||||
|
||||
assertDisplayed(R.id.roomProfileAvatarView)
|
||||
|
||||
// Leave
|
||||
// Room addresses
|
||||
clickListItem(R.id.matrixProfileRecyclerView, 13)
|
||||
onView(isRoot()).perform(waitForView(withText(R.string.room_alias_published_alias_title)))
|
||||
pressBack()
|
||||
|
||||
// Room permissions
|
||||
clickListItem(R.id.matrixProfileRecyclerView, 15)
|
||||
onView(isRoot()).perform(waitForView(withText(R.string.room_permissions_title)))
|
||||
clickOn(R.string.room_permissions_change_room_avatar)
|
||||
clickDialogNegativeButton()
|
||||
// Toggle
|
||||
clickOn(R.string.show_advanced)
|
||||
clickOn(R.string.hide_advanced)
|
||||
pressBack()
|
||||
|
||||
// Leave
|
||||
clickListItem(R.id.matrixProfileRecyclerView, 17)
|
||||
clickDialogNegativeButton()
|
||||
|
||||
// Menu share
|
||||
@ -289,27 +304,12 @@ class UiAllScreensSanityTest {
|
||||
}
|
||||
|
||||
private fun navigateToRoomParameters() {
|
||||
// Room addresses
|
||||
clickListItem(R.id.roomSettingsRecyclerView, 4)
|
||||
onView(isRoot()).perform(waitForView(withText(R.string.room_alias_published_alias_title)))
|
||||
pressBack()
|
||||
|
||||
// Room permissions
|
||||
clickListItem(R.id.roomSettingsRecyclerView, 6)
|
||||
onView(isRoot()).perform(waitForView(withText(R.string.room_permissions_title)))
|
||||
clickOn(R.string.room_permissions_change_room_avatar)
|
||||
clickDialogNegativeButton()
|
||||
// Toggle
|
||||
clickOn(R.string.show_advanced)
|
||||
clickOn(R.string.hide_advanced)
|
||||
pressBack()
|
||||
|
||||
// Room history readability
|
||||
clickListItem(R.id.roomSettingsRecyclerView, 8)
|
||||
clickListItem(R.id.roomSettingsRecyclerView, 4)
|
||||
pressBack()
|
||||
|
||||
// Room access
|
||||
clickListItem(R.id.roomSettingsRecyclerView, 10)
|
||||
clickListItem(R.id.roomSettingsRecyclerView, 6)
|
||||
pressBack()
|
||||
}
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user