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

This commit is contained in:
David Langley 2021-08-10 10:54:22 +01:00
commit 7f3c4f0073
206 changed files with 6606 additions and 761 deletions

View file

@ -1,3 +1,30 @@
Changes in Element v1.1.16 (2021-08-09)
=======================================
Features ✨
----------
- Spaces - Support Restricted Room via room capabilities API ([#3509](https://github.com/vector-im/element-android/issues/3509))
- Spaces | Support restricted room access in room settings ([#3665](https://github.com/vector-im/element-android/issues/3665))
Bugfixes 🐛
----------
- Fix crash when opening Troubleshoot Notifications ([#3778](https://github.com/vector-im/element-android/issues/3778))
- Fix error when sending encrypted message if someone in the room logs out. ([#3792](https://github.com/vector-im/element-android/issues/3792))
- Voice Message - Amplitude update java.util.ConcurrentModificationException ([#3796](https://github.com/vector-im/element-android/issues/3796))
Changes in Element v1.1.15 (2021-07-30)
=======================================
Features ✨
----------
- Voice Message implementation (Currently under Labs Settings and disabled by default). ([#3598](https://github.com/vector-im/element-android/issues/3598))
SDK API changes ⚠️
------------------
- updatePushRuleActions signature has been updated to more explicitly enabled/disable the rule and update the actions. It's behaviour has also been changed to match the web with the enable/disable requests being sent on every invocation and actions sent when needed(not null). ([#3681](https://github.com/vector-im/element-android/issues/3681))
Changes in Element 1.1.14 (2021-07-23)
======================================

View file

@ -48,6 +48,9 @@ allprojects {
// Chat effects
includeGroupByRegex 'com\\.github\\.jetradarmobile'
includeGroupByRegex 'nl\\.dionsegijn'
// Voice RecordView
includeGroupByRegex 'com\\.github\\.Armen101'
}
}
maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }

View file

@ -1 +0,0 @@
updatePushRuleActions signature has been updated to more explicitly enabled/disable the rule and update the actions. It's behaviour has also been changed to match the web with the enable/disable requests being sent on every invocation and actions sent when needed(not null).

View file

@ -0,0 +1,2 @@
Hlavní změny v této verzi: aktualizace motivu a stylu a oprava pádu aplikace po videohovoru
Úplný seznam změn: https://github.com/vector-im/element-android/releases/tag/v1.1.12

View file

@ -0,0 +1,2 @@
Hlavní změny v této verzi: aktualizace hlavně kvůli stabilitě a opravám chyb
Úplný seznam změn: https://github.com/vector-im/element-android/releases/tag/v1.1.13

View file

@ -0,0 +1,2 @@
Hlavní změny v této verzi: oprava chyby ohledně šifrovaných zpráv
Úplný seznam změn: https://github.com/vector-im/element-android/releases/tag/v1.1.14

View file

@ -0,0 +1,2 @@
Hauptänderung dieser Version: Beheben eines Problems mit verschlüsselten Nachrichten.
Alle Änderungen: https://github.com/vector-im/element-android/releases/tag/v1.1.14

View file

@ -0,0 +1,2 @@
Main changes in this version: voice message implementation under labs settings.
Full changelog: https://github.com/vector-im/element-android/releases/tag/v1.1.15

View file

@ -0,0 +1,2 @@
Main changes in this version: Fix error when sending encrypted message if someone in the room logs out.
Full changelog: https://github.com/vector-im/element-android/releases/tag/v1.1.16

View file

@ -0,0 +1,2 @@
Põhilised muutused selles versioonis: teemade ja välimuse uuendused ning videokõne-järgse kokkujooksmise parandused
Kogu ingliskeelne muudatuste logi: https://github.com/vector-im/element-android/releases/tag/v1.1.12

View file

@ -0,0 +1,2 @@
Põhilised muutused selles versioonis: üldiste vigade parandus.
Kogu ingliskeelne muudatuste logi: https://github.com/vector-im/element-android/releases/tag/v1.1.13

View file

@ -0,0 +1,2 @@
Põhilised muutused selles versioonis: krüptitud sõnumitega seotud vigade parandus
Kogu ingliskeelne muudatuste logi: https://github.com/vector-im/element-android/releases/tag/v1.1.14

View file

@ -0,0 +1,2 @@
Főbb változtatások ebben a verzióban: kinézet és stílus frissítések és a videóhívás utáni összeomlás javítása
Teljes változásnapló: https://github.com/vector-im/element-android/releases/tag/v1.1.12

View file

@ -0,0 +1,2 @@
Fő változás ebben a verzióban: leginkább hibajavító és stabilitást növelő frissítés
Teljes változásnapló: https://github.com/vector-im/element-android/releases/tag/v1.1.13

View file

@ -0,0 +1,2 @@
Fő változás ebben a verzióban: titkosított üzenetekkel kapcsolatos hibajavítás
Teljes változásnapló: https://github.com/vector-im/element-android/releases/tag/v1.1.14

View file

@ -0,0 +1,2 @@
Versi baru ini terutama berisi perbaikan bug dan peningkatan. Mengirim pesan sekarang jauh lebih cepat.
Changelog lanjutan: https://github.com/vector-im/element-android/releases/tag/v1.0.10

View file

@ -0,0 +1,2 @@
Versi baru ini terutama berisi antarmuka pengguna dan peningkatan pengalaman pengguna. Sekarang Anda dapat mengundang teman, dan membuat sebuah DM sangat cepat dengan memindai kode QR.
Changelog lanjutan: https://github.com/vector-im/element-android/releases/tag/v1.0.11

View file

@ -0,0 +1,2 @@
Perubahan utama dalam versi ini: Pratinjau URL, keyboard Emoji baru, kemampuan pengaturan ruangan baru, dan salju untuk Natal!
Changelog lanjutan: https://github.com/vector-im/element-android/releases/tag/v1.0.12

View file

@ -0,0 +1,2 @@
Perubahan utama dalam versi ini: Pratinjau URL, keyboard Emoji baru, kemampuan pengaturan ruangan baru, dan salju untuk Natal!
Changelog lanjutan: https://github.com/vector-im/element-android/releases/tag/v1.0.13

View file

@ -0,0 +1,2 @@
Perubahan utama dalam versi ini: Edit izin ruangan, tema cahaya/gelap otomatis, dan banyak perbaikan bug.
Changelog lanjutan: https://github.com/vector-im/element-android/releases/tag/v1.0.14

View file

@ -0,0 +1,2 @@
Perubahan utama dalam versi ini: Dukungan login sosial.
Changelog lanjutan: https://github.com/vector-im/element-android/releases/tag/v1.0.15

View file

@ -0,0 +1,2 @@
Perubahan utama dalam versi ini: Dukungan login sosial.
Changelog lanjutan: https://github.com/vector-im/element-android/releases/tag/v1.0.15 dan https://github.com/vector-im/element-android/releases/tag/v1.0.16

View file

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

View file

@ -0,0 +1,2 @@
Perubahan utama dalam versi ini: perbaikan VoIP (panggilan audio dan video dalam DM) dan perbaikan bug!
Changelog lanjutan: https://github.com/vector-im/element-android/releases/tag/v1.1.0

View file

@ -0,0 +1,2 @@
Perubahan utama dalam versi ini: peningkatan kinerja dan perbaikan bug!
Changelog lanjutan: https://github.com/vector-im/element-android/releases/tag/v1.1.1

View file

@ -0,0 +1,2 @@
Perubahan utama dalam versi ini: peningkatan kinerja dan perbaikan bug!
Changelog lanjutan: https://github.com/vector-im/element-android/releases/tag/v1.1.2

View file

@ -0,0 +1,2 @@
Perubahan utama dalam versi ini: peningkatan kinerja dan perbaikan bug!
Changelog lanjutan: https://github.com/vector-im/element-android/releases/tag/v1.1.3

View file

@ -0,0 +1,2 @@
Perubahan utama dalam versi ini: peningkatan kinerja dan perbaikan bug!
Changelog lanjutan: https://github.com/vector-im/element-android/releases/tag/v1.1.4

View file

@ -0,0 +1,2 @@
Perubahan utama dalam versi ini: perbaikan hot-fix untuk 1.1.4
Changelog lanjutan: https://github.com/vector-im/element-android/releases/tag/v1.1.5

View file

@ -0,0 +1,2 @@
Perubahan utama dalam versi ini: perbaikan hot-fix untuk 1.1.5
Changelog lanjutan: https://github.com/vector-im/element-android/releases/tag/v1.1.6

View file

@ -0,0 +1,2 @@
Perubahan utama dalam versi ini: dukungan beta untuk Spaces. Kompres video sebelum mengirim.
Changelog lanjutan: https://github.com/vector-im/element-android/releases/tag/v1.1.7

View file

@ -0,0 +1,2 @@
Perubahan utama dalam versi ini: perbaikan untuk Spaces.
Changelog lanjutan: https://github.com/vector-im/element-android/releases/tag/v1.1.8

View file

@ -0,0 +1,2 @@
Perubahan utama dalam versi ini: menambahkan dukungan untuk jaringan gitter.im.
Changelog lanjutan: https://github.com/vector-im/element-android/releases/tag/v1.1.9

View file

@ -0,0 +1,2 @@
Perubahan utama dalam versi ini: pembaruan tema dan gaya dan fitur-fitur baru untuk Spaces.
Changelog lanjutan: https://github.com/vector-im/element-android/releases/tag/v1.1.10

View file

@ -0,0 +1,2 @@
Perubahan utama dalam versi ini: pembaruan tema dan gaya dan fitur baru untuk spaces (perbaikan bug untuk 1.1.10)
Changelog lanjutan: https://github.com/vector-im/element-android/releases/tag/v1.1.11

View file

@ -0,0 +1,2 @@
Perubahan utama dalam versi ini: pembaruan tema dan gaya dan perbaiki crash setelah panggilan video
Changelog lanjutan: https://github.com/vector-im/element-android/releases/tag/v1.1.12

View file

@ -0,0 +1,2 @@
Perubahan utama dalam versi ini: terutama pembaruan stabilitas dan perbaikan bug.
Changelog lanjutan: https://github.com/vector-im/element-android/releases/tag/v1.1.13

View file

@ -0,0 +1,2 @@
Perubahan utama dalam versi ini: memperbaiki masalah tentang pesan terenkripsi.
Changelog lanjutan: https://github.com/vector-im/element-android/releases/tag/v1.1.14

View file

@ -0,0 +1,39 @@
Element adalah perpesanan yang aman dan aplikasi kolaborasi tim produktivitas yang ideal untuk obrolan grup saat bekerja jarak jauh. Aplikasi obrolan ini menggunakan enkripsi ujung-ke-ujung untuk memberikan konferensi video, berbagi file, dan panggilan suara.
<b>Fitur Element termasuk:</b>
- Alat komunikasi online yang canggih
- Pesan terenkripsi sepenuhnya untuk memungkinkan komunikasi perusahaan yang lebih aman, bahkan untuk pekerja jarak jauh
- Obrolan terdesentralisasi berdasarkan framework sumber-terbuka Matrix
- Berbagi file dengan aman dengan data terenkripsi saat mengelola proyek
- Obrolan video dengan VoIP dan berbagi layar
- Integrasi yang mudah dengan alat kolaborasi online favorit Anda, alat manajemen proyek, layanan VoIP dan aplikasi perpesanan tim lainnya
Element benar-benar berbeda dari aplikasi perpesanan dan kolaborasi lainnya. Ini beroperasi pada Matrix, jaringan terbuka untuk pengiriman pesan yang aman dan komunikasi terdesentralisasi. Ini memungkinkan hosting sendiri untuk memberi pengguna kepemilikan maksimum dan kontrol data dan pesan mereka.
<b>Pesan privasi dan terenkripsi</b>
Element melindungi Anda dari iklan yang tidak diinginkan, data penambangan dan taman berdinding. Ini juga mengamankan semua data Anda, komunikasi video dan suara satu-ke-satu melalui enkripsi ujung-ke-ujung dan verifikasi perangkat yang di-cross-signed.
Element memberi Anda kendali atas privasi Anda sambil memungkinkan Anda untuk berkomunikasi dengan aman dengan siapa pun di jaringan Matrix, atau alat kolaborasi bisnis lainnya dengan mengintegrasikan dengan aplikasi seperti Slack.
<b>Element dapat dihost sendiri</b>
Untuk memungkinkan lebih banyak kendali atas data dan percakapan sensitif Anda, Element bisa dihost sendiri atau Anda dapat memilih host berbasis Matrix - standar untuk komunikasi terdesentralisasi sumber-terbuka. Element memberi Anda privasi, kepatuhan keamanan, dan fleksibilitas integrasi.
<b>Miliki data Anda</b>
Anda memutuskan di mana menyimpan data dan pesan Anda. Tanpa risiko penambangan data atau akses dari pihak ketiga.
Element menempatkan Anda dalam kendali dengan cara yang berbeda:
1. Dapatkan akun gratis pada server publik matrix.org yang dihost oleh pengembang Matrix, atau memilih dari ribuan server publik yang dihost oleh sukarelawan
2. Host sendiri akun Anda dengan menjalankan server pada infrastruktur IT Anda sendiri
3. Daftar untuk akun di server khusus dengan hanya berlangganan platform hosting Element Matrix Services
<b>Pesan terbuka dan kolaborasi</b>
Anda dapat mengobrol dengan siapa saja di jaringan Matrix, apakah mereka menggunakan Element, aplikasi Matrix lain atau bahkan jika mereka menggunakan aplikasi perpesanan yang berbeda.
<b>Sangat aman</b>
Enkripsi ujung-ke-ujung beneran (hanya mereka yang dalam percakapan dapat mendekripsi pesan), dan verifikasi perangkat yang di-cross-signed.
<b>Komunikasi dan integrasi lengkap</b>
Perpesanan, panggilan suara dan video, berbagi file, berbagi layar dan banyak integrasi, bot dan widget. Buat ruangan, komunitas, tetap terhubung dan selesaikan hal-hal.
<b>Ambil di mana Anda tinggalkan</b>
Tetap terhubung di mana pun Anda berada dengan riwayat pesan yang sepenuhnya disinkronkan di semua perangkat Anda dan di web di https://app.element.io

View file

@ -0,0 +1 @@
Perpesanan grup - pesan terenkripsi, panggilan grup dan video

View file

@ -0,0 +1 @@
Element - Perpesanan Aman

View file

@ -0,0 +1,2 @@
Modifiche principali in questa versione: aggiornati tema e stile, corretto un crash dopo videochiamata
Cronologia completa: https://github.com/vector-im/element-android/releases/tag/v1.1.12

View file

@ -0,0 +1,2 @@
Modifiche principali in questa versione: aggiornamento di stabilità e correzione errori.
Cronologia completa: https://github.com/vector-im/element-android/releases/tag/v1.1.13

View file

@ -0,0 +1,2 @@
Modifiche principali in questa versione: corretto un problema con i messaggi cifrati.
Cronologia completa: https://github.com/vector-im/element-android/releases/tag/v1.1.14

View file

@ -0,0 +1,2 @@
Principais mudanças nesta versão: atualização de tema e estilo e consertar um crash depois de chamada de vídeo
Changelog completo: https://github.com/vector-im/element-android/releases/tag/v1.1.12

View file

@ -0,0 +1,2 @@
Principais mudanças nesta versão: principalmente atualização de estabilidade e consertos de bug.
Changelog completo: https://github.com/vector-im/element-android/releases/tag/v1.1.13

View file

@ -0,0 +1,2 @@
Principais mudanças nesta versão: consertar um problema sobre mensagens encriptadas.
Changelog completo: https://github.com/vector-im/element-android/releases/tag/v1.1.14

View file

@ -0,0 +1,2 @@
Основные изменения в этой версии: улучшение и исправления ошибок!
Полный список изменений: https://github.com/vector-im/element-android/releases/tag/v1.1.4

View file

@ -0,0 +1,2 @@
Основные изменения в этой версии: исправление для 1.1.4
Полный список изменений: https://github.com/vector-im/element-android/releases/tag/v1.1.5

View file

@ -0,0 +1,2 @@
Основные изменения в этой версии: исправление для 1.1.5
Полный список изменений: https://github.com/vector-im/element-android/releases/tag/v1.1.6

View file

@ -0,0 +1,2 @@
Основные изменения в этой версии: бета-поддержка Пространств. Сжатие видео перед отправкой.
Полный список изменений: https://github.com/vector-im/element-android/releases/tag/v1.1.7

View file

@ -0,0 +1,2 @@
Основные изменения в этой версии: Усовершенствованы Пространства!
Полный список изменений: https://github.com/vector-im/element-android/releases/tag/v1.1.8

View file

@ -0,0 +1,2 @@
Основные изменения в этой версии: добавлена поддержка сети gitter.im.
Полный список изменений: https://github.com/vector-im/element-android/releases/tag/v1.1.9

View file

@ -0,0 +1,2 @@
Основные изменения этой версии: обновлен внешний вид и новые возможности для пространств
Полный список изменений: https://github.com/vector-im/element-android/releases/tag/v1.1.10

View file

@ -0,0 +1,2 @@
Основные изменения этой версии: обновлен внешний вид и новые возможности для пространств (bugfix для 1.1.10)
Полный список изменений: https://github.com/vector-im/element-android/releases/tag/v1.1.11

View file

@ -0,0 +1,2 @@
Основные изменения в этой версии: обновление темы и стиля и исправления сбоев после видеовызова
Полный список изменений: https://github.com/vector-im/element-android/releases/tag/v1.1.12

View file

@ -0,0 +1,2 @@
Основные изменения в этой версии: улучшение стабильности и исправления ошибок.
Полный список изменений: https://github.com/vector-im/element-android/releases/tag/v1.1.13

View file

@ -0,0 +1,2 @@
Основные изменения в этой версии: исправление проблемы с зашифрованными сообщениями.
Полный список изменений: https://github.com/vector-im/element-android/releases/tag/v1.1.14

View file

@ -1,30 +1,39 @@
Element - это новый тип приложения для обмена сообщениями и совместной работы, которое:
Element - это одновременно безопасный мессенджер и приложение для совместной работы, которое идеально подходит для групповых чатов при удаленной работе. Это приложение для чатов использует сквозное шифрование для обеспечения мощных видеоконференций, обмена файлами и голосовых звонков.
1. Позволяет вам контролировать вашу конфиденциальность
2. Позволяет общаться с кем угодно в сети Matrix и даже за ее пределами за счет интеграции с такими приложениями, как Slack
3. Защищает вас от рекламы, данных и огороженных стеной садов
4. Обеспечивает безопасность с помощью сквозного шифрования с перекрестной подписью для проверки других пользователей
<b>Особенности Element включают:</b>
- Передовые средства онлайн-общения
- Полностью зашифрованные сообщения, обеспечивающие безопасное корпоративное общение даже для удаленных работников
- Децентрализованный чат на базе платформы Matrix с открытым исходным кодом
- Безопасный обмен файлами с зашифрованными данными при управлении проектами
- Видеочаты с VoIP и совместным использованием экрана
- Простая интеграция с вашими любимыми инструментами для совместной работы в Интернете, средствами управления проектами, VoIP-сервисами и другими приложениями для обмена сообщениями в команде.
Element полностью отличается от других приложений для обмена сообщениями и совместной работы, потому что он децентрализован и имеет открытый исходный код.
Element полностью отличается от других приложений для обмена сообщениями и совместной работы. Он работает на базе Matrix, открытой сети для безопасного обмена сообщениями и децентрализованного общения. Он позволяет самостоятельно размещать свои данные и сообщения, предоставляя пользователям максимальный контроль над ними.
Element позволяет вам самостоятельно размещать или выбирать хост-узел, чтобы у вас была конфиденциальность, право собственности и контроль над своими данными и разговорами. Он предоставляет вам доступ к открытой сети, поэтому вы не ограничены общением исключительно с пользователями Element. И он очень надежен и безопаснен.
<b>Приватность и зашифрованный обмен сообщениями</b>.
Element защищает вас от нежелательной рекламы, сбора данных и "садов". Он также защищает все ваши данные, видео- и голосовую связь один на один благодаря сквозному шифрованию и перекрестной проверке устройств.
Element может делать все это, потому что он работает на Matrix - стандарте открытого, децентрализованного общения.
Element дает вам контроль над вашей конфиденциальностью, позволяя безопасно общаться с любым человеком в сети Matrix или с другими инструментами совместной работы благодаря интеграции с такими приложениями, как Slack.
Element предоставляет вам полный контроль, позволяя выбрать поставщиков услуг, обслуживающих серверы с вашими беседами. Вы свободны выбрать любой способ размещения прямо из приложения Element:
<b>Element может быть размещен самостоятельно</b>.
Чтобы обеспечить больший контроль над конфиденциальными данными и разговорами, Element может быть размещен самостоятельно или вы можете выбрать любой хост на базе Matrix - стандарт децентрализованного общения с открытым исходным кодом. Element обеспечивает конфиденциальность, соответствие требованиям безопасности и гибкость интеграции.
1. Получить бесплатную учетную запись на общедоступном сервере matrix.org, размещенном разработчиками Matrix, или выберите один из тысяч общедоступных серверов, размещенных волонтерами.
2. Разместить свою учетную запись на собственном сервере
3. Зарегистрироваться на индивидуальном сервере, просто подписавшись на услуги платформы Element Matrix Services
<b>Владение своими данными</b>.
Вы сами решаете, где хранить свои данные и сообщения. Без риска добычи данных или доступа третьих лиц.
<b>Почему выбирают Element?</b>
Element дает вам возможность контролировать ситуацию различными способами:
1. Получить бесплатный аккаунт на публичном сервере matrix.org, размещенном разработчиками Matrix, или выбрать один из тысяч публичных серверов, размещенных добровольцами.
2. Самостоятельно разместить свою учетную запись, запустив сервер на собственной IT-инфраструктуре.
3. Зарегистрировать учетную запись на пользовательском сервере, просто подписавшись на хостинг-платформу Element Matrix Services.
<b>СОБСТВЕННЫЕ ДАННЫЕ</b>: Вы решаете, где хранить свои данные и сообщения. Вы владеете ими и контролируете их, а не какая-то мегакорпорация, что собирает ваши данные и предоставляет сторонним лицам доступ к ним.
<b>Открытый обмен сообщениями и сотрудничество</b>.
Вы можете общаться с любым человеком в сети Matrix, независимо от того, использует ли он Element, другое приложение Matrix или даже если он использует другое приложение для обмена сообщениями.
<b>ОТКРЫТОЕ ОБЩЕНИЕ И СОТРУДНИЧЕСТВО</b>: Вы можете общаться с кем угодно в сети Matrix, независимо от того, используют ли они приложение Element или другое приложение Matrix, и даже если они используют другую систему обмена сообщениями, такую как Slack, IRC или XMPP.
<b>Супербезопасно</b>
Настоящее сквозное шифрование (только участники разговора могут расшифровывать сообщения) и проверка устройств с перекрестной подписью.
<b>СУПЕР-БЕЗОПАСНОСТЬ</b>: Настоящее сквозное шифрование (только участники разговора могут расшифровывать сообщения) и перекрестная подпись для проверки устройств участников разговора.
<b>Полная коммуникация и интеграция</b>.
Обмен сообщениями, голосовые и видеозвонки, совместное использование файлов, совместное использование экрана и целый ряд интеграций, ботов и виджетов. Создавайте комнаты, сообщества, оставайтесь на связи и выполняйте задачи.
<b>ПОЛНАЯ КОММУНИКАЦИЯ</b>: Обмен сообщениями, голосовые и видеозвонки, совместное использование файлов, совместное использование экрана и целый ряд интеграций, ботов и виджетов. Создавайте комнаты, сообщества, оставайтесь на связи и добивайтесь результатов.
<b>ВЫ ВЕЗДЕ</b>: Оставайтесь на связи, где бы вы ни находились, благодаря полностью синхронизированной истории сообщений на всех ваших устройствах и в Интернете по адресу https://app.element.io.
<b>Восстанавливайте связь с того места, где остановились</b>.
Оставайтесь на связи, где бы вы ни находились, с полностью синхронизированной историей сообщений на всех ваших устройствах и в Интернете по адресу https://app.element.io

View file

@ -1 +1 @@
Защищённый децентрализованный чат и звонки. Держите ваши данные в безопасности.
Групповой мессенджер - зашифрованные сообщения, групповые беседы и видеовызовы

View file

@ -1 +1 @@
Element (ранее Riot.im)
Element - Безопасный мессенджер

View file

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

View file

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

View file

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

View file

@ -0,0 +1,2 @@
此版本中的主要變動:佈景主題與樣式更新,以及修復視訊通話後當機的問題
完整的變更紀錄https://github.com/vector-im/element-android/releases/tag/v1.1.12

View file

@ -0,0 +1,2 @@
此版本中的主要變動:主要是穩定性與臭蟲修復更新。
完整的變更紀錄https://github.com/vector-im/element-android/releases/tag/v1.1.13

View file

@ -0,0 +1,2 @@
此版本中的主要變動:修復關於加密訊息的問題。
完整的變更紀錄https://github.com/vector-im/element-android/releases/tag/v1.1.14

View file

@ -60,4 +60,6 @@ dependencies {
implementation 'com.github.vector-im:PFLockScreen-Android:1.0.0-beta12'
// dialpad dimen
implementation 'im.dlg:android-dialer:1.2.5'
// AudioRecordView attr
implementation 'com.github.Armen101:AudioRecordView:1.0.5'
}

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#F00" />
<corners android:radius="8dp" />
</shape>

View file

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<integer name="rtl_x_multiplier">-1</integer>
<integer name="rtl_mirror_flip">180</integer>
</resources>

View file

@ -128,4 +128,8 @@
<color name="vctr_chat_effect_snow_background_light">@color/black_alpha</color>
<color name="vctr_chat_effect_snow_background_dark">@android:color/transparent</color>
<attr name="vctr_voice_message_toast_background" format="color" />
<color name="vctr_voice_message_toast_background_light">@color/palette_black_900</color>
<color name="vctr_voice_message_toast_background_dark">@color/palette_gray_400</color>
</resources>

View file

@ -7,6 +7,7 @@
<integer name="default_animation_offset">200</integer>
<integer name="rtl_x_multiplier">1</integer>
<integer name="rtl_mirror_flip">0</integer>
<integer name="splash_animation_velocity">750</integer>

View file

@ -23,7 +23,7 @@
<!-- For light themes -->
<color name="palette_gray_25">#F4F6FA</color>
<color name="palette_gray_50">#E6E8F0</color>
<color name="palette_gray_50">#E3E8F0</color>
<color name="palette_gray_100">#C1C6CD</color>
<color name="palette_gray_150">#8D97A5</color>
<color name="palette_gray_200">#737D8C</color>

View file

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="VoicePlaybackWaveform">
<item name="chunkColor">?vctr_content_secondary</item>
<item name="chunkAlignTo">center</item>
<item name="chunkMinHeight">1dp</item>
<item name="chunkRoundedCorners">true</item>
<item name="chunkSoftTransition">true</item>
<item name="chunkSpace">2dp</item>
<item name="chunkWidth">2dp</item>
<item name="direction">rightToLeft</item>
</style>
<style name="Widget.Vector.TextView.Caption.Toast">
<item name="android:paddingTop">8dp</item>
<item name="android:paddingBottom">8dp</item>
<item name="android:paddingStart">12dp</item>
<item name="android:paddingEnd">12dp</item>
<item name="android:background">@drawable/bg_round_corner_8dp</item>
<item name="android:backgroundTint">?vctr_voice_message_toast_background</item>
<item name="android:textColor">@color/palette_white</item>
<item name="android:gravity">center</item>
</style>
</resources>

View file

@ -135,6 +135,8 @@
<item name="vctr_jump_to_unread_style">@style/Widget.Vector.JumpToUnread.Dark</item>
<!-- Voice Message -->
<item name="vctr_voice_message_toast_background">@color/vctr_voice_message_toast_background_dark</item>
</style>
<style name="Theme.Vector.Dark" parent="Base.Theme.Vector.Dark" />

View file

@ -137,6 +137,8 @@
<item name="vctr_jump_to_unread_style">@style/Widget.Vector.JumpToUnread.Light</item>
<!-- Voice Message -->
<item name="vctr_voice_message_toast_background">@color/vctr_voice_message_toast_background_light</item>
</style>
<style name="Theme.Vector.Light" parent="Base.Theme.Vector.Light" />

View file

@ -23,6 +23,7 @@ import io.reactivex.Single
import kotlinx.coroutines.rx2.rxCompletable
import kotlinx.coroutines.rx2.rxSingle
import org.matrix.android.sdk.api.query.QueryStringValue
import org.matrix.android.sdk.api.session.content.ContentAttachmentData
import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.identity.ThreePid
import org.matrix.android.sdk.api.session.room.Room
@ -146,6 +147,10 @@ class RxRoom(private val room: Room) {
fun deleteAvatar(): Completable = rxCompletable {
room.deleteAvatar()
}
fun sendMedia(attachment: ContentAttachmentData, compressBeforeSending: Boolean, roomIds: Set<String>): Completable = rxCompletable {
room.sendMedia(attachment, compressBeforeSending, roomIds)
}
}
fun Room.rx(): RxRoom {

View file

@ -35,7 +35,8 @@ data class ContentAttachmentData(
val name: String? = null,
val queryUri: Uri,
val mimeType: String?,
val type: Type
val type: Type,
val waveform: List<Int>? = null
) : Parcelable {
@JsonClass(generateAdapter = false)

View file

@ -40,7 +40,63 @@ data class HomeServerCapabilities(
*/
val roomVersions: RoomVersionCapabilities? = null
) {
enum class RoomCapabilitySupport {
SUPPORTED,
SUPPORTED_UNSTABLE,
UNSUPPORTED,
UNKNOWN
}
/**
* Check if a feature is supported by the homeserver.
* @return
* UNKNOWN if the server does not implement room caps
* UNSUPPORTED if this feature is not supported
* SUPPORTED if this feature is supported by a stable version
* SUPPORTED_UNSTABLE if this feature is supported by an unstable version
* (unstable version should only be used for dev/experimental purpose)
*/
fun isFeatureSupported(feature: String): RoomCapabilitySupport {
if (roomVersions?.capabilities == null) return RoomCapabilitySupport.UNKNOWN
val info = roomVersions.capabilities[feature] ?: return RoomCapabilitySupport.UNSUPPORTED
val preferred = info.preferred ?: info.support.lastOrNull()
val versionCap = roomVersions.supportedVersion.firstOrNull { it.version == preferred }
return when {
versionCap == null -> {
RoomCapabilitySupport.UNKNOWN
}
versionCap.status == RoomVersionStatus.STABLE -> {
RoomCapabilitySupport.SUPPORTED
}
else -> {
RoomCapabilitySupport.SUPPORTED_UNSTABLE
}
}
}
fun isFeatureSupported(feature: String, byRoomVersion: String): Boolean {
if (roomVersions?.capabilities == null) return false
val info = roomVersions.capabilities[feature] ?: return false
return info.preferred == byRoomVersion || info.support.contains(byRoomVersion)
}
/**
* Use this method to know if you should force a version when creating
* a room that requires this feature.
* You can also use #isFeatureSupported prior to this call to check if the
* feature is supported and report some feedback to user.
*/
fun versionOverrideForFeature(feature: String) : String? {
val cap = roomVersions?.capabilities?.get(feature)
return cap?.preferred ?: cap?.support?.lastOrNull()
}
companion object {
const val MAX_UPLOAD_FILE_SIZE_UNKNOWN = -1L
const val ROOM_CAP_KNOCK = "knock"
const val ROOM_CAP_RESTRICTED = "restricted"
}
}

View file

@ -18,7 +18,9 @@ package org.matrix.android.sdk.api.session.homeserver
data class RoomVersionCapabilities(
val defaultRoomVersion: String,
val supportedVersion: List<RoomVersionInfo>
val supportedVersion: List<RoomVersionInfo>,
// Keys are capabilities defined per spec, as for now knock or restricted
val capabilities: Map<String, RoomCapabilitySupport>?
)
data class RoomVersionInfo(
@ -26,6 +28,11 @@ data class RoomVersionInfo(
val status: RoomVersionStatus
)
data class RoomCapabilitySupport(
val preferred: String?,
val support: List<String>
)
enum class RoomVersionStatus {
STABLE,
UNSTABLE

View file

@ -22,7 +22,6 @@ import org.matrix.android.sdk.api.session.room.model.GuestAccess
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
import org.matrix.android.sdk.api.session.room.model.RoomDirectoryVisibility
import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibility
import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesAllowEntry
import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM
open class CreateRoomParams {
@ -162,7 +161,7 @@ open class CreateRoomParams {
var roomVersion: String? = null
var joinRuleRestricted: List<RoomJoinRulesAllowEntry>? = null
var featurePreset: RoomFeaturePreset? = null
companion object {
private const val CREATION_CONTENT_KEY_M_FEDERATE = "m.federate"

View file

@ -0,0 +1,56 @@
/*
* 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.create
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.toContent
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities
import org.matrix.android.sdk.api.session.room.model.GuestAccess
import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibility
import org.matrix.android.sdk.api.session.room.model.RoomJoinRules
import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesAllowEntry
import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesContent
interface RoomFeaturePreset {
fun updateRoomParams(params: CreateRoomParams)
fun setupInitialStates(): List<Event>?
}
class RestrictedRoomPreset(val homeServerCapabilities: HomeServerCapabilities, val restrictedList: List<RoomJoinRulesAllowEntry>) : RoomFeaturePreset {
override fun updateRoomParams(params: CreateRoomParams) {
params.historyVisibility = params.historyVisibility ?: RoomHistoryVisibility.SHARED
params.guestAccess = params.guestAccess ?: GuestAccess.Forbidden
params.roomVersion = homeServerCapabilities.versionOverrideForFeature(HomeServerCapabilities.ROOM_CAP_RESTRICTED)
}
override fun setupInitialStates(): List<Event>? {
return listOf(
Event(
type = EventType.STATE_ROOM_JOIN_RULES,
stateKey = "",
content = RoomJoinRulesContent(
_joinRules = RoomJoinRules.RESTRICTED.value,
allowList = restrictedList
).toContent()
)
)
}
}

View file

@ -24,15 +24,15 @@ data class AudioInfo(
/**
* The mimetype of the audio e.g. "audio/aac".
*/
@Json(name = "mimetype") val mimeType: String?,
@Json(name = "mimetype") val mimeType: String? = null,
/**
* The size of the audio clip in bytes.
*/
@Json(name = "size") val size: Long = 0,
@Json(name = "size") val size: Long? = null,
/**
* The duration of the audio in milliseconds.
*/
@Json(name = "duration") val duration: Int = 0
@Json(name = "duration") val duration: Int? = null
)

View file

@ -0,0 +1,36 @@
/*
* 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.message
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
/**
* See https://github.com/matrix-org/matrix-doc/blob/travis/msc/audio-waveform/proposals/3246-audio-waveform.md
*/
@JsonClass(generateAdapter = true)
data class AudioWaveformInfo(
@Json(name = "duration")
val duration: Int? = null,
/**
* The array should have no less than 30 elements and no more than 120.
* List of integers between zero and 1024, inclusive.
*/
@Json(name = "waveform")
val waveform: List<Int>? = null
)

View file

@ -20,6 +20,7 @@ import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import org.matrix.android.sdk.api.session.events.model.Content
import org.matrix.android.sdk.api.session.room.model.relation.RelationDefaultContent
import org.matrix.android.sdk.api.util.JsonDict
import org.matrix.android.sdk.internal.crypto.model.rest.EncryptedFileInfo
@JsonClass(generateAdapter = true)
@ -50,7 +51,17 @@ data class MessageAudioContent(
/**
* Required if the file is encrypted. Information on the encrypted file, as specified in End-to-end encryption.
*/
@Json(name = "file") override val encryptedFileInfo: EncryptedFileInfo? = null
@Json(name = "file") override val encryptedFileInfo: EncryptedFileInfo? = null,
/**
* Encapsulates waveform and duration of the audio.
*/
@Json(name = "org.matrix.msc1767.audio") val audioWaveformInfo: AudioWaveformInfo? = null,
/**
* Indicates that is a voice message.
*/
@Json(name = "org.matrix.msc3245.voice") val voiceMessageIndicator: JsonDict? = null
) : MessageWithAttachmentContent {
override val mimeType: String?

View file

@ -23,6 +23,7 @@ import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.room.model.GuestAccess
import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibility
import org.matrix.android.sdk.api.session.room.model.RoomJoinRules
import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesAllowEntry
import org.matrix.android.sdk.api.util.JsonDict
import org.matrix.android.sdk.api.util.Optional
@ -53,7 +54,7 @@ interface StateService {
/**
* Update the join rule and/or the guest access
*/
suspend fun updateJoinRule(joinRules: RoomJoinRules?, guestAccess: GuestAccess?)
suspend fun updateJoinRule(joinRules: RoomJoinRules?, guestAccess: GuestAccess?, allowList: List<RoomJoinRulesAllowEntry>? = null)
/**
* Update the avatar of the room
@ -91,4 +92,8 @@ interface StateService {
* @param eventTypes Set of eventType to observe. If empty, all state events will be observed
*/
fun getStateEventsLive(eventTypes: Set<String>, stateKey: QueryStringValue = QueryStringValue.NoCondition): LiveData<List<Event>>
suspend fun setJoinRulePublic()
suspend fun setJoinRuleInviteOnly()
suspend fun setJoinRuleRestricted(allowList: List<String>)
}

View file

@ -31,6 +31,8 @@ object MimeTypes {
const val Jpeg = "image/jpeg"
const val Gif = "image/gif"
const val Ogg = "audio/ogg"
fun String?.normalizeMimeType() = if (this == BadJpg) Jpeg else this
fun String?.isMimeTypeImage() = this?.startsWith("image/").orFalse()

View file

@ -49,6 +49,8 @@ internal class DefaultSessionCreator @Inject constructor(
// remove trailing "/"
?.trim { it == '/' }
?.takeIf { it.isNotBlank() }
// It can be the same value, so in this case, do not check again the validity
?.takeIf { it != homeServerConnectionConfig.homeServerUriBase.toString() }
?.also { Timber.d("Overriding homeserver url to $it (will check if valid)") }
?.let { Uri.parse(it) }
?.takeIf {

View file

@ -18,8 +18,6 @@ package org.matrix.android.sdk.internal.crypto.model
import org.matrix.android.sdk.internal.crypto.crosssigning.DeviceTrustLevel
import org.matrix.android.sdk.internal.crypto.model.rest.DeviceKeys
import org.matrix.android.sdk.internal.crypto.model.rest.UnsignedDeviceInfo
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMapper
import org.matrix.android.sdk.internal.crypto.store.db.model.DeviceInfoEntity
data class CryptoDeviceInfo(
val deviceId: String,
@ -77,7 +75,3 @@ data class CryptoDeviceInfo(
internal fun CryptoDeviceInfo.toRest(): DeviceKeys {
return CryptoInfoMapper.map(this)
}
internal fun CryptoDeviceInfo.toEntity(): DeviceInfoEntity {
return CryptoMapper.mapToEntity(this)
}

View file

@ -51,7 +51,6 @@ import org.matrix.android.sdk.internal.crypto.model.OutboundGroupSessionWrapper
import org.matrix.android.sdk.internal.crypto.model.event.RoomKeyWithHeldContent
import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo
import org.matrix.android.sdk.internal.crypto.model.rest.RoomKeyRequestBody
import org.matrix.android.sdk.internal.crypto.model.toEntity
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
import org.matrix.android.sdk.internal.crypto.store.PrivateKeysInfo
import org.matrix.android.sdk.internal.crypto.store.SavedKeyBackupKeyInfo
@ -280,24 +279,37 @@ internal class RealmCryptoStore @Inject constructor(
override fun storeUserDevices(userId: String, devices: Map<String, CryptoDeviceInfo>?) {
doRealmTransaction(realmConfiguration) { realm ->
if (devices == null) {
Timber.d("Remove user $userId")
// Remove the user
UserEntity.delete(realm, userId)
} else {
UserEntity.getOrCreate(realm, userId)
.let { u ->
// Add the devices
val currentKnownDevices = u.devices.toList()
val new = devices.map { entry -> entry.value.toEntity() }
new.forEach { entity ->
// Maintain first time seen
val existing = currentKnownDevices.firstOrNull { it.deviceId == entity.deviceId && it.identityKey == entity.identityKey }
entity.firstTimeSeenLocalTs = existing?.firstTimeSeenLocalTs ?: System.currentTimeMillis()
realm.insertOrUpdate(entity)
}
// Ensure all other devices are deleted
u.devices.clearWith { it.deleteOnCascade() }
u.devices.addAll(new)
val userEntity = UserEntity.getOrCreate(realm, userId)
// First delete the removed devices
val deviceIds = devices.keys
userEntity.devices.toTypedArray().iterator().let {
while (it.hasNext()) {
val deviceInfoEntity = it.next()
if (deviceInfoEntity.deviceId !in deviceIds) {
Timber.d("Remove device ${deviceInfoEntity.deviceId} of user $userId")
deviceInfoEntity.deleteOnCascade()
}
}
}
// Then update existing devices or add new one
devices.values.forEach { cryptoDeviceInfo ->
val existingDeviceInfoEntity = userEntity.devices.firstOrNull { it.deviceId == cryptoDeviceInfo.deviceId }
if (existingDeviceInfoEntity == null) {
// Add the device
Timber.d("Add device ${cryptoDeviceInfo.deviceId} of user $userId")
val newEntity = CryptoMapper.mapToEntity(cryptoDeviceInfo)
newEntity.firstTimeSeenLocalTs = System.currentTimeMillis()
userEntity.devices.add(newEntity)
} else {
// Update the device
Timber.d("Update device ${cryptoDeviceInfo.deviceId} of user $userId")
CryptoMapper.updateDeviceInfoEntity(existingDeviceInfoEntity, cryptoDeviceInfo)
}
}
}
}
}

View file

@ -55,7 +55,7 @@ internal object RealmCryptoStoreMigration : RealmMigration {
// 0, 1, 2: legacy Riot-Android
// 3: migrate to RiotX schema
// 4, 5, 6, 7, 8, 9: migrations from RiotX (which was previously 1, 2, 3, 4, 5, 6)
const val CRYPTO_STORE_SCHEMA_VERSION = 12L
const val CRYPTO_STORE_SCHEMA_VERSION = 13L
private fun RealmObjectSchema.addFieldIfNotExists(fieldName: String, fieldType: Class<*>): RealmObjectSchema {
if (!hasField(fieldName)) {
@ -93,6 +93,7 @@ internal object RealmCryptoStoreMigration : RealmMigration {
if (oldVersion <= 9) migrateTo10(realm)
if (oldVersion <= 10) migrateTo11(realm)
if (oldVersion <= 11) migrateTo12(realm)
if (oldVersion <= 12) migrateTo13(realm)
}
private fun migrateTo1Legacy(realm: DynamicRealm) {
@ -497,4 +498,60 @@ internal object RealmCryptoStoreMigration : RealmMigration {
realm.schema.get("CryptoRoomEntity")
?.addRealmObjectField(CryptoRoomEntityFields.OUTBOUND_SESSION_INFO.`$`, outboundEntitySchema)
}
// Version 13L delete unreferenced TrustLevelEntity
private fun migrateTo13(realm: DynamicRealm) {
Timber.d("Step 12 -> 13")
// Use a trick to do that... Ref: https://stackoverflow.com/questions/55221366
val trustLevelEntitySchema = realm.schema.get("TrustLevelEntity")
/*
Creating a new temp field called isLinked which is set to true for those which are
references by other objects. Rest of them are set to false. Then removing all
those which are false and hence duplicate and unnecessary. Then removing the temp field
isLinked
*/
var mainCounter = 0
var deviceInfoCounter = 0
var keyInfoCounter = 0
val deleteCounter: Int
trustLevelEntitySchema
?.addField("isLinked", Boolean::class.java)
?.transform { obj ->
// Setting to false for all by default
obj.set("isLinked", false)
mainCounter++
}
realm.schema.get("DeviceInfoEntity")?.transform { obj ->
// Setting to true for those which are referenced in DeviceInfoEntity
deviceInfoCounter++
obj.getObject("trustLevelEntity")?.set("isLinked", true)
}
realm.schema.get("KeyInfoEntity")?.transform { obj ->
// Setting to true for those which are referenced in KeyInfoEntity
keyInfoCounter++
obj.getObject("trustLevelEntity")?.set("isLinked", true)
}
// Removing all those which are set as false
realm.where("TrustLevelEntity")
.equalTo("isLinked", false)
.findAll()
.also { deleteCounter = it.size }
.deleteAllFromRealm()
trustLevelEntitySchema?.removeField("isLinked")
Timber.w("TrustLevelEntity cleanup: $mainCounter entities")
Timber.w("TrustLevelEntity cleanup: $deviceInfoCounter entities referenced in DeviceInfoEntities")
Timber.w("TrustLevelEntity cleanup: $keyInfoCounter entities referenced in KeyInfoEntity")
Timber.w("TrustLevelEntity cleanup: $deleteCounter entities deleted!")
if (mainCounter != deviceInfoCounter + keyInfoCounter + deleteCounter) {
Timber.e("TrustLevelEntity cleanup: Something is not correct...")
}
}
}

View file

@ -44,23 +44,32 @@ object CryptoMapper {
))
internal fun mapToEntity(deviceInfo: CryptoDeviceInfo): DeviceInfoEntity {
return DeviceInfoEntity(
primaryKey = DeviceInfoEntity.createPrimaryKey(deviceInfo.userId, deviceInfo.deviceId),
userId = deviceInfo.userId,
deviceId = deviceInfo.deviceId,
algorithmListJson = listMigrationAdapter.toJson(deviceInfo.algorithms),
keysMapJson = mapMigrationAdapter.toJson(deviceInfo.keys),
signatureMapJson = mapMigrationAdapter.toJson(deviceInfo.signatures),
isBlocked = deviceInfo.isBlocked,
trustLevelEntity = deviceInfo.trustLevel?.let {
TrustLevelEntity(
crossSignedVerified = it.crossSigningVerified,
locallyVerified = it.locallyVerified
)
},
// We store the device name if present now
unsignedMapJson = deviceInfo.unsigned?.deviceDisplayName
)
return DeviceInfoEntity(primaryKey = DeviceInfoEntity.createPrimaryKey(deviceInfo.userId, deviceInfo.deviceId))
.also { updateDeviceInfoEntity(it, deviceInfo) }
}
internal fun updateDeviceInfoEntity(entity: DeviceInfoEntity, deviceInfo: CryptoDeviceInfo) {
entity.userId = deviceInfo.userId
entity.deviceId = deviceInfo.deviceId
entity.algorithmListJson = listMigrationAdapter.toJson(deviceInfo.algorithms)
entity.keysMapJson = mapMigrationAdapter.toJson(deviceInfo.keys)
entity.signatureMapJson = mapMigrationAdapter.toJson(deviceInfo.signatures)
entity.isBlocked = deviceInfo.isBlocked
val deviceInfoTrustLevel = deviceInfo.trustLevel
if (deviceInfoTrustLevel == null) {
entity.trustLevelEntity?.deleteFromRealm()
entity.trustLevelEntity = null
} else {
if (entity.trustLevelEntity == null) {
// Create a new TrustLevelEntity object
entity.trustLevelEntity = TrustLevelEntity()
}
// Update the existing TrustLevelEntity object
entity.trustLevelEntity?.crossSignedVerified = deviceInfoTrustLevel.crossSigningVerified
entity.trustLevelEntity?.locallyVerified = deviceInfoTrustLevel.locallyVerified
}
// We store the device name if present now
entity.unsignedMapJson = deviceInfo.unsigned?.deviceDisplayName
}
internal fun mapToModel(deviceInfoEntity: DeviceInfoEntity): CryptoDeviceInfo {

View file

@ -18,6 +18,7 @@ package org.matrix.android.sdk.internal.database.mapper
import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities
import org.matrix.android.sdk.api.session.homeserver.RoomCapabilitySupport
import org.matrix.android.sdk.api.session.homeserver.RoomVersionCapabilities
import org.matrix.android.sdk.api.session.homeserver.RoomVersionInfo
import org.matrix.android.sdk.api.session.homeserver.RoomVersionStatus
@ -45,19 +46,28 @@ internal object HomeServerCapabilitiesMapper {
roomVersionsJson ?: return null
return tryOrNull {
MoshiProvider.providesMoshi().adapter(RoomVersions::class.java).fromJson(roomVersionsJson)?.let {
MoshiProvider.providesMoshi().adapter(RoomVersions::class.java).fromJson(roomVersionsJson)?.let { roomVersions ->
RoomVersionCapabilities(
defaultRoomVersion = it.default ?: DefaultRoomVersionService.DEFAULT_ROOM_VERSION,
supportedVersion = it.available.entries.map { entry ->
RoomVersionInfo(
version = entry.key,
status = if (entry.value == "stable") {
RoomVersionStatus.STABLE
} else {
RoomVersionStatus.UNSTABLE
}
)
}
defaultRoomVersion = roomVersions.default ?: DefaultRoomVersionService.DEFAULT_ROOM_VERSION,
supportedVersion = roomVersions.available?.entries?.map { entry ->
RoomVersionInfo(entry.key, RoomVersionStatus.STABLE
.takeIf { entry.value == "stable" }
?: RoomVersionStatus.UNSTABLE)
}.orEmpty(),
capabilities = roomVersions.roomCapabilities?.entries?.mapNotNull { entry ->
(entry.value as? Map<*, *>)?.let {
val preferred = it["preferred"] as? String ?: return@mapNotNull null
val support = (it["support"] as? List<*>)?.filterIsInstance<String>()
entry.key to RoomCapabilitySupport(preferred, support.orEmpty())
}
}?.toMap()
// Just for debug purpose
// ?: mapOf(
// HomeServerCapabilities.ROOM_CAP_RESTRICTED to RoomCapabilitySupport(
// preferred = null,
// support = listOf("org.matrix.msc3083")
// )
// )
)
}
}

View file

@ -25,6 +25,7 @@ import kotlinx.coroutines.completeWith
import kotlinx.coroutines.withContext
import okhttp3.OkHttpClient
import okhttp3.Request
import org.matrix.android.sdk.api.failure.Failure
import org.matrix.android.sdk.api.session.content.ContentUrlResolver
import org.matrix.android.sdk.api.session.file.FileService
import org.matrix.android.sdk.internal.crypto.attachments.ElementToDecrypt
@ -124,13 +125,21 @@ internal class DefaultFileService @Inject constructor(
.header(DOWNLOAD_PROGRESS_INTERCEPTOR_HEADER, url)
.build()
val response = okHttpClient.newCall(request).execute()
if (!response.isSuccessful) {
throw IOException()
val response = try {
okHttpClient.newCall(request).execute()
} catch (failure: Throwable) {
throw if (failure is IOException) {
Failure.NetworkConnection(failure)
} else {
failure
}
}
val source = response.body?.source() ?: throw IOException()
if (!response.isSuccessful) {
throw Failure.NetworkConnection(IOException())
}
val source = response.body?.source() ?: throw Failure.NetworkConnection(IOException())
Timber.v("Response size ${response.body?.contentLength()} - Stream available: ${!source.exhausted()}")

View file

@ -70,7 +70,22 @@ internal data class RoomVersions(
* Required. A detailed description of the room versions the server supports.
*/
@Json(name = "available")
val available: JsonDict
val available: JsonDict? = null,
/**
* "room_capabilities": {
* "knock" : {
* "preferred": "7",
* "support" : ["7"]
* },
* "restricted" : {
* "preferred": "9",
* "support" : ["8", "9"]
* }
* }
*/
@Json(name = "room_capabilities")
val roomCapabilities: JsonDict? = null
)
// The spec says: If not present, the client should assume that password changes are possible via the API

View file

@ -17,17 +17,24 @@
package org.matrix.android.sdk.internal.session.permalinks
import org.matrix.android.sdk.api.MatrixPatterns.getDomain
import org.matrix.android.sdk.api.query.QueryStringValue
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.members.roomMemberQueryParams
import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
import org.matrix.android.sdk.internal.di.UserId
import org.matrix.android.sdk.internal.session.room.RoomGetter
import org.matrix.android.sdk.internal.session.room.state.StateEventDataSource
import java.net.URLEncoder
import javax.inject.Inject
import javax.inject.Provider
internal class ViaParameterFinder @Inject constructor(
@UserId private val userId: String,
private val roomGetterProvider: Provider<RoomGetter>
private val roomGetterProvider: Provider<RoomGetter>,
private val stateEventDataSource: StateEventDataSource
) {
fun computeViaParams(roomId: String, max: Int): List<String> {
@ -70,4 +77,28 @@ internal class ViaParameterFinder @Inject constructor(
.orEmpty()
.toSet()
}
fun computeViaParamsForRestricted(roomId: String, max: Int): List<String> {
val userThatCanInvite = roomGetterProvider.get().getRoom(roomId)
?.getRoomMembers(roomMemberQueryParams { memberships = listOf(Membership.JOIN) })
?.map { it.userId }
?.filter { userCanInvite(userId, roomId) }
.orEmpty()
.toSet()
return userThatCanInvite.map { it.getDomain() }
.groupBy { it }
.mapValues { it.value.size }
.toMutableMap()
.let { map -> map.keys.sortedByDescending { map[it] } }
.take(max)
}
fun userCanInvite(userId: String, roomId: String): Boolean {
val powerLevelsHelper = stateEventDataSource.getStateEvent(roomId, EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.NoCondition)
?.content?.toModel<PowerLevelsContent>()
?.let { PowerLevelsHelper(it) }
return powerLevelsHelper?.isUserAbleToInvite(userId) ?: false
}
}

View file

@ -17,16 +17,10 @@
package org.matrix.android.sdk.internal.session.room.create
import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.session.crypto.crosssigning.CrossSigningService
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.toContent
import org.matrix.android.sdk.api.session.identity.IdentityServiceError
import org.matrix.android.sdk.api.session.identity.toMedium
import org.matrix.android.sdk.api.session.room.model.GuestAccess
import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibility
import org.matrix.android.sdk.api.session.room.model.RoomJoinRules
import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesContent
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
import org.matrix.android.sdk.api.util.MimeTypes
import org.matrix.android.sdk.internal.crypto.DeviceListManager
@ -45,7 +39,6 @@ import javax.inject.Inject
internal class CreateRoomBodyBuilder @Inject constructor(
private val ensureIdentityTokenTask: EnsureIdentityTokenTask,
private val crossSigningService: CrossSigningService,
private val deviceListManager: DeviceListManager,
private val identityStore: IdentityStore,
private val fileUploader: FileUploader,
@ -76,19 +69,18 @@ internal class CreateRoomBodyBuilder @Inject constructor(
}
}
if (params.joinRuleRestricted != null) {
params.roomVersion = "org.matrix.msc3083"
params.historyVisibility = params.historyVisibility ?: RoomHistoryVisibility.SHARED
params.guestAccess = params.guestAccess ?: GuestAccess.Forbidden
}
val initialStates = (listOfNotNull(
buildEncryptionWithAlgorithmEvent(params),
buildHistoryVisibilityEvent(params),
buildAvatarEvent(params),
buildGuestAccess(params),
buildJoinRulesRestricted(params)
)
+ buildCustomInitialStates(params))
params.featurePreset?.updateRoomParams(params)
val initialStates = (
listOfNotNull(
buildEncryptionWithAlgorithmEvent(params),
buildHistoryVisibilityEvent(params),
buildAvatarEvent(params),
buildGuestAccess(params)
)
+ params.featurePreset?.setupInitialStates().orEmpty()
+ buildCustomInitialStates(params)
)
.takeIf { it.isNotEmpty() }
return CreateRoomBody(
@ -158,20 +150,6 @@ internal class CreateRoomBodyBuilder @Inject constructor(
}
}
private fun buildJoinRulesRestricted(params: CreateRoomParams): Event? {
return params.joinRuleRestricted
?.let { allowList ->
Event(
type = EventType.STATE_ROOM_JOIN_RULES,
stateKey = "",
content = RoomJoinRulesContent(
_joinRules = RoomJoinRules.RESTRICTED.value,
allowList = allowList
).toContent()
)
}
}
/**
* Add the crypto algorithm to the room creation parameters.
*/

View file

@ -184,7 +184,8 @@ internal class DefaultSendService @AssistedInject constructor(
mimeType = messageContent.mimeType,
name = messageContent.body,
queryUri = Uri.parse(messageContent.url),
type = ContentAttachmentData.Type.AUDIO
type = ContentAttachmentData.Type.AUDIO,
waveform = messageContent.audioWaveformInfo?.waveform
)
localEchoRepository.updateSendState(localEcho.eventId, roomId, SendState.UNSENT)
internalSendMedia(listOf(localEcho.root), attachmentData, true)

View file

@ -29,6 +29,7 @@ import org.matrix.android.sdk.api.session.events.model.RelationType
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.room.model.message.AudioInfo
import org.matrix.android.sdk.api.session.room.model.message.AudioWaveformInfo
import org.matrix.android.sdk.api.session.room.model.message.FileInfo
import org.matrix.android.sdk.api.session.room.model.message.ImageInfo
import org.matrix.android.sdk.api.session.room.model.message.MessageAudioContent
@ -74,6 +75,7 @@ internal class LocalEchoEventFactory @Inject constructor(
private val markdownParser: MarkdownParser,
private val textPillsUtils: TextPillsUtils,
private val thumbnailExtractor: ThumbnailExtractor,
private val waveformSanitizer: WaveFormSanitizer,
private val localEchoRepository: LocalEchoRepository,
private val permalinkFactory: PermalinkFactory
) {
@ -289,14 +291,21 @@ internal class LocalEchoEventFactory @Inject constructor(
}
private fun createAudioEvent(roomId: String, attachment: ContentAttachmentData): Event {
val isVoiceMessage = attachment.waveform != null
val content = MessageAudioContent(
msgType = MessageType.MSGTYPE_AUDIO,
body = attachment.name ?: "audio",
audioInfo = AudioInfo(
duration = attachment.duration?.toInt(),
mimeType = attachment.getSafeMimeType()?.takeIf { it.isNotBlank() },
size = attachment.size
),
url = attachment.queryUri.toString()
url = attachment.queryUri.toString(),
audioWaveformInfo = if (!isVoiceMessage) null else AudioWaveformInfo(
duration = attachment.duration?.toInt(),
waveform = waveformSanitizer.sanitize(attachment.waveform)
),
voiceMessageIndicator = if (!isVoiceMessage) null else emptyMap()
)
return createMessageEvent(roomId, content)
}

View file

@ -0,0 +1,86 @@
/*
* 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.room.send
import timber.log.Timber
import javax.inject.Inject
import kotlin.math.abs
import kotlin.math.ceil
internal class WaveFormSanitizer @Inject constructor() {
private companion object {
const val MIN_NUMBER_OF_VALUES = 30
const val MAX_NUMBER_OF_VALUES = 120
const val MAX_VALUE = 1024
}
/**
* The array should have no less than 30 elements and no more than 120.
* List of integers between zero and 1024, inclusive.
*/
fun sanitize(waveForm: List<Int>?): List<Int>? {
if (waveForm.isNullOrEmpty()) {
return null
}
// Limit the number of items
val sizeInRangeList = mutableListOf<Int>()
when {
waveForm.size < MIN_NUMBER_OF_VALUES -> {
// Repeat the same value to have at least 30 items
val repeatTimes = ceil(MIN_NUMBER_OF_VALUES / waveForm.size.toDouble()).toInt()
waveForm.map { value ->
repeat(repeatTimes) {
sizeInRangeList.add(value)
}
}
}
waveForm.size > MAX_NUMBER_OF_VALUES -> {
val keepOneOf = ceil(waveForm.size.toDouble() / MAX_NUMBER_OF_VALUES).toInt()
waveForm.mapIndexed { idx, value ->
if (idx % keepOneOf == 0) {
sizeInRangeList.add(value)
}
}
}
else -> {
sizeInRangeList.addAll(waveForm)
}
}
// OK, ensure all items are positive
val positiveList = sizeInRangeList.map {
abs(it)
}
// Ensure max is not above MAX_VALUE
val max = positiveList.maxOrNull() ?: MAX_VALUE
val finalList = if (max > MAX_VALUE) {
// Reduce the values
positiveList.map {
it * MAX_VALUE / max
}
} else {
positiveList
}
Timber.d("Sanitize from ${waveForm.size} items to ${finalList.size} items. Max value was $max")
return finalList
}
}

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