Merge tag 'v1.4.34' into sc

Change-Id: I7e1939f6c87e14d1497433a9bad4f97e074bb838

Conflicts:
	vector/src/debug/java/im/vector/app/flipper/VectorFlipperProxy.kt
	vector/src/main/java/im/vector/app/core/di/ActiveSessionHolder.kt
	vector/src/main/java/im/vector/app/features/home/HomeActivity.kt
	vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListAction.kt
	vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt
	vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListViewModel.kt
	vector/src/main/java/im/vector/app/features/settings/VectorSettingsAdvancedSettingsFragment.kt
	vector/src/main/res/layout/fragment_login_server_url_form_2.xml
	vector/src/main/res/layout/fragment_room_list.xml
This commit is contained in:
SpiritCroc 2022-08-24 09:45:24 +02:00
commit e6023c6bae
349 changed files with 4372 additions and 7619 deletions

View file

@ -21,6 +21,8 @@ body:
- [ ] While Weblate is locked, and after the PR from Weblate has been merged, handle all the TODOs in the main `strings.xml` file - [ ] While Weblate is locked, and after the PR from Weblate has been merged, handle all the TODOs in the main `strings.xml` file
- [ ] Run the script `./tools/release/pushPlayStoreMetaData.sh`. You can check in the GooglePlay console the Activity log to check the effect. - [ ] Run the script `./tools/release/pushPlayStoreMetaData.sh`. You can check in the GooglePlay console the Activity log to check the effect.
- [ ] Ensure all [the required PRs](https://github.com/vector-im/element-android/pulls?q=is%3Aopen+is%3Apr+label%3AZ-NextRelease) have been merged
### Do the release ### Do the release
- [ ] Make sure `develop` and `main` are up to date (git pull) - [ ] Make sure `develop` and `main` are up to date (git pull)

View file

@ -16,3 +16,5 @@ jobs:
args: "--dangerfile tools/danger/dangerfile.js" args: "--dangerfile tools/danger/dangerfile.js"
env: env:
DANGER_GITHUB_API_TOKEN: ${{ secrets.DANGER_GITHUB_API_TOKEN }} DANGER_GITHUB_API_TOKEN: ${{ secrets.DANGER_GITHUB_API_TOKEN }}
# Fallback for forks
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View file

@ -71,6 +71,8 @@ jobs:
args: "--dangerfile tools/danger/dangerfile-lint.js" args: "--dangerfile tools/danger/dangerfile-lint.js"
env: env:
DANGER_GITHUB_API_TOKEN: ${{ secrets.DANGER_GITHUB_API_TOKEN }} DANGER_GITHUB_API_TOKEN: ${{ secrets.DANGER_GITHUB_API_TOKEN }}
# Fallback for forks
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Gradle dependency analysis using https://github.com/autonomousapps/dependency-analysis-android-gradle-plugin # Gradle dependency analysis using https://github.com/autonomousapps/dependency-analysis-android-gradle-plugin
dependency-analysis: dependency-analysis:

View file

@ -98,7 +98,8 @@ jobs:
# Skip in forks # Skip in forks
if: > if: >
github.repository == 'vector-im/element-android' && github.repository == 'vector-im/element-android' &&
(contains(github.event.issue.labels.*.name, 'Team: Delight')) (contains(github.event.issue.labels.*.name, 'Team: Delight') ||
contains(github.event.issue.labels.*.name, 'Z-AppLayout'))
steps: steps:
- uses: octokit/graphql-action@v2.x - uses: octokit/graphql-action@v2.x
with: with:

View file

@ -1,3 +1,51 @@
Changes in Element v1.4.34 (2022-08-23)
=======================================
Features ✨
----------
- [Notification] - Handle creation of notification for live location and poll start ([#6746](https://github.com/vector-im/element-android/issues/6746))
Bugfixes 🐛
----------
- Fixes onboarding requiring matrix.org to be accessible on the first step, the server can now be manually changed ([#6718](https://github.com/vector-im/element-android/issues/6718))
- Fixing sign in/up for homeservers that rely on the SSO fallback url ([#6827](https://github.com/vector-im/element-android/issues/6827))
- Fixes uncaught exceptions in the SyncWorker to cause the worker to become stuck in the failure state ([#6836](https://github.com/vector-im/element-android/issues/6836))
- Fixes onboarding captcha crashing when no WebView is available by showing an error with information instead ([#6855](https://github.com/vector-im/element-android/issues/6855))
- Removes ability to continue registration after the app has been destroyed, fixes the next steps crashing due to missing information from the previous steps ([#6860](https://github.com/vector-im/element-android/issues/6860))
- Fixes crash when exiting the login or registration entry screens whilst they're loading ([#6861](https://github.com/vector-im/element-android/issues/6861))
- Fixes server selection being unable to trust certificates ([#6864](https://github.com/vector-im/element-android/issues/6864))
- Ensure SyncThread is started when the app is launched after a Push has been received. ([#6884](https://github.com/vector-im/element-android/issues/6884))
- Fixes missing firebase notifications after logging in when UnifiedPush distributor is installed ([#6891](https://github.com/vector-im/element-android/issues/6891))
In development 🚧
----------------
- Create DM room only on first message - Trigger the flow when the "Direct Message" action is selected from the room member details screen ([#5525](https://github.com/vector-im/element-android/issues/5525))
- added filter tabs for new App layout's Home screen ([#6505](https://github.com/vector-im/element-android/issues/6505))
- [App Layout] added dialog to configure app layout ([#6506](https://github.com/vector-im/element-android/issues/6506))
- Adds space list bottom sheet for new app layout ([#6749](https://github.com/vector-im/element-android/issues/6749))
- [App Layout] Dialpad moved from bottom navigation tab to a separate activity accessed via home screen context menu ([#6787](https://github.com/vector-im/element-android/issues/6787))
- Makes toolbar switch title based on space in New App Layout ([#6795](https://github.com/vector-im/element-android/issues/6795))
- [Devices management] Add a feature flag and empty screen for future new layout ([#6798](https://github.com/vector-im/element-android/issues/6798))
- Adds new chat bottom sheet as the click action of the main FAB in the new app layout ([#6801](https://github.com/vector-im/element-android/issues/6801))
- [Devices management] Other sessions section in new layout ([#6806](https://github.com/vector-im/element-android/issues/6806))
- [New Layout] Adds space settings accessible through clicking the toolbar ([#6859](https://github.com/vector-im/element-android/issues/6859))
- Adds New App Layout FABs (hidden behind feature flag) ([#6693](https://github.com/vector-im/element-android/issues/6693))
SDK API changes ⚠️
------------------
- Rename `DebugService.logDbUsageInfo` (resp. `Session.logDbUsageInfo`) to `DebugService.getDbUsageInfo` (resp. `Session.getDbUsageInfo`) and return a String instead of logging. The caller may want to log the String. ([#6884](https://github.com/vector-im/element-android/issues/6884))
Other changes
-------------
- Removes the Login2 proof of concept - replaced by the FTUE changes ([#5974](https://github.com/vector-im/element-android/issues/5974))
- Enable auto-capitalization for Room creation Title field ([#6645](https://github.com/vector-im/element-android/issues/6645))
- Decouples the variant logic from the vector module ([#6783](https://github.com/vector-im/element-android/issues/6783))
- Add a developer setting to enable LeakCanary at runtime ([#6786](https://github.com/vector-im/element-android/issues/6786))
- [Create Room] Reduce some boilerplate with room state event contents ([#6799](https://github.com/vector-im/element-android/issues/6799))
- [Call] Memory leak after a call ([#6808](https://github.com/vector-im/element-android/issues/6808))
- Fix some string template ([#6843](https://github.com/vector-im/element-android/issues/6843))
Changes in Element v1.4.32 (2022-08-10) Changes in Element v1.4.32 (2022-08-10)
======================================= =======================================

View file

@ -24,7 +24,7 @@ buildscript {
classpath libs.gradle.gradlePlugin classpath libs.gradle.gradlePlugin
classpath libs.gradle.kotlinPlugin classpath libs.gradle.kotlinPlugin
classpath libs.gradle.hiltPlugin classpath libs.gradle.hiltPlugin
classpath 'com.google.firebase:firebase-appdistribution-gradle:3.0.2' classpath 'com.google.firebase:firebase-appdistribution-gradle:3.0.3'
classpath 'com.google.gms:google-services:4.3.13' classpath 'com.google.gms:google-services:4.3.13'
classpath 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.4.0.2513' classpath 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.4.0.2513'
classpath 'com.google.android.gms:oss-licenses-plugin:0.10.5' classpath 'com.google.android.gms:oss-licenses-plugin:0.10.5'
@ -44,7 +44,7 @@ plugins {
id "io.gitlab.arturbosch.detekt" version "1.21.0" id "io.gitlab.arturbosch.detekt" version "1.21.0"
// Dependency Analysis // Dependency Analysis
id 'com.autonomousapps.dependency-analysis' version "1.11.2" id 'com.autonomousapps.dependency-analysis' version "1.12.0"
} }
// https://github.com/jeremylong/DependencyCheck // https://github.com/jeremylong/DependencyCheck
@ -151,6 +151,8 @@ allprojects {
"experimental:comment-wrapping", "experimental:comment-wrapping",
// - A KDoc comment after any other element on the same line must be separated by a new line // - A KDoc comment after any other element on the same line must be separated by a new line
"experimental:kdoc-wrapping", "experimental:kdoc-wrapping",
// Ignore error "Redundant curly braces", since we use it to fix false positives, for instance in "elementLogs.${i}.txt"
"string-template",
] ]
} }

View file

@ -22,7 +22,7 @@ def markwon = "4.6.2"
def moshi = "1.13.0" def moshi = "1.13.0"
def lifecycle = "2.5.1" def lifecycle = "2.5.1"
def flowBinding = "1.2.0" def flowBinding = "1.2.0"
def flipper = "0.156.0" def flipper = "0.157.0"
def epoxy = "4.6.2" def epoxy = "4.6.2"
def mavericks = "2.7.0" def mavericks = "2.7.0"
def glide = "4.13.2" def glide = "4.13.2"
@ -30,7 +30,7 @@ def bigImageViewer = "1.8.1"
def jjwt = "0.11.5" def jjwt = "0.11.5"
def vanniktechEmoji = "0.15.0" def vanniktechEmoji = "0.15.0"
def fragment = "1.5.1" def fragment = "1.5.2"
// Testing // Testing
def mockk = "1.12.3" // We need to use 1.12.3 to have mocking in androidTest until a new version is released: https://github.com/mockk/mockk/issues/819 def mockk = "1.12.3" // We need to use 1.12.3 to have mocking in androidTest until a new version is released: https://github.com/mockk/mockk/issues/819

View file

@ -108,7 +108,9 @@ ext.groups = [
'com.pinterest.ktlint', 'com.pinterest.ktlint',
'com.posthog.android', 'com.posthog.android',
'com.squareup', 'com.squareup',
'com.squareup.curtains',
'com.squareup.duktape', 'com.squareup.duktape',
'com.squareup.leakcanary',
'com.squareup.moshi', 'com.squareup.moshi',
'com.squareup.okhttp3', 'com.squareup.okhttp3',
'com.squareup.okio', 'com.squareup.okio',

View file

@ -23,6 +23,7 @@ Here are the checks that Danger does so far:
- PR description is not empty - PR description is not empty
- Big PR got a warning to recommend to split - Big PR got a warning to recommend to split
- PR contains a file for towncrier and extension is checked - PR contains a file for towncrier and extension is checked
- PR does not modify frozen classes
- PR contains a Sign-Off, with exception for Element employee contributors - PR contains a Sign-Off, with exception for Element employee contributors
- PR with change on layout should include screenshot in the description - PR with change on layout should include screenshot in the description
- PR which adds png file warn about the usage of vector drawables - PR which adds png file warn about the usage of vector drawables
@ -84,6 +85,8 @@ To let Danger check all the PRs, including PRs form forks, a GitHub account have
- password: Stored on Passbolt - password: Stored on Passbolt
- GitHub token: A token with limited access has been created and added to the repository https://github.com/vector-im/element-android as secret DANGER_GITHUB_API_TOKEN. This token is not saved anywhere else. In case of problem, just delete it and create a new one, then update the secret. - GitHub token: A token with limited access has been created and added to the repository https://github.com/vector-im/element-android as secret DANGER_GITHUB_API_TOKEN. This token is not saved anywhere else. In case of problem, just delete it and create a new one, then update the secret.
PRs from forks do not always have access to the secret `secrets.DANGER_GITHUB_API_TOKEN`, so `secrets.GITHUB_TOKEN` is also provided to the job environment. If `secrets.DANGER_GITHUB_API_TOKEN` is available, it will be used, so user `ElementBot` will comment the PR. Else `secrets.GITHUB_TOKEN` will be used, and bot `github-actions` will comment the PR.
## Useful links ## Useful links
- https://danger.systems/ - https://danger.systems/

View file

@ -0,0 +1,2 @@
Hlavní změny v této verzi: Umožňuje vylepšené přihlašování a registraci.
Úplný seznam změn: https://github.com/vector-im/element-android/releases

View file

@ -0,0 +1,2 @@
Hlavní změny v této verzi: Umožňuje vylepšené přihlašování a registraci.
Úplný seznam změn: https://github.com/vector-im/element-android/releases

View file

@ -0,0 +1,2 @@
Main changes in this version: Various bug fixes and stability improvements.
Full changelog: https://github.com/vector-im/element-android/releases

View file

@ -0,0 +1,2 @@
Põhilised muutused selles versioonis: senisest parem liitumise ja sisselogimise töövoog.
Kogu ingliskeelne muudatuste logi: https://github.com/vector-im/element-android/releases

View file

@ -0,0 +1,2 @@
Põhilised muutused selles versioonis: senisest parem liitumise ja sisselogimise töövoog.
Kogu ingliskeelne muudatuste logi: https://github.com/vector-im/element-android/releases

View file

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

View file

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

View file

@ -0,0 +1,2 @@
Principaux changements pour cette version : Activation de lauthentification et du parcours dinscription améliorés.
Intégralité des changements : https://github.com/vector-im/element-android/releases

View file

@ -0,0 +1,2 @@
Principaux changements pour cette version : Activation de lauthentification et du parcours dinscription améliorés.
Intégralité des changements : https://github.com/vector-im/element-android/releases

View file

@ -0,0 +1,2 @@
Perubahan utama dalam versi ini: Mengaktifkan perjalanan masuk dan keluar yang diperbaiki.
Catatan perubahan lanjutan: https://github.com/vector-im/element-android/releases

View file

@ -0,0 +1,2 @@
Perubahan utama dalam versi ini: Mengaktifkan perjalanan masuk dan keluar yang diperbaiki.
Catatan perubahan lanjutan: https://github.com/vector-im/element-android/releases

View file

@ -1,42 +1,42 @@
Element adalah perpesanan yang aman dan aplikasi kolaborasi tim produktivitas yang ideal untuk obrolan grup saat bekerja jarak jauh. Aplikasi perpesanan ini menggunakan enkripsi ujung-ke-ujung untuk memberikan konferensi video, pembagian file, dan panggilan suara yang aman. Element adalah perpesanan yang aman dan aplikasi kolaborasi tim produktivitas yang ideal untuk obrolan grup saat bekerja jarak jauh. Aplikasi perpesanan ini menggunakan enkripsi ujung-ke-ujung untuk menyediakan konferensi video, pembagian berkas, dan panggilan suara yang aman.
<b>Fitur Element termasuk</b> <b>Fitur Element termasuk:</b>
- Alat komunikasi online yang canggih - Alat komunikasi daring yang canggih
- Pesan-pesan yang dienkripsi sepenuhnya untuk memungkinkan komunikasi perusahaan yang lebih aman, bahkan untuk pekerja jarak jauh - Pesan-pesan yang dienkripsi sepenuhnya untuk memungkinkan komunikasi perusahaan yang lebih aman, bahkan untuk pekerja jarak jauh
- Obrolan terdesentralisasi berdasarkan kerangka Matrix yang sumber terbuka - Obrolan terdesentralisasi berdasarkan kerangka kerja Matrix yang sumber terbuka
- Pembagian file aman dengan data terenkripsi saat mengelola proyek - Pembagian berkas aman dengan data terenkripsi saat mengelola proyek
- Obrolan video dengan VoIP dan pembagian layar - Obrolan video dengan VoIP dan pembagian layar
- Integrasi yang mudah dengan alat kolaborasi online favorit Anda, alat manajemen proyek, layanan VoIP dan aplikasi perpesanan tim lainnya - Integrasi yang mudah dengan alat kolaborasi daring favorit Anda, alat pengelola proyek, layanan VoIP dan aplikasi perpesanan tim lainnya
Element benar-benar berbeda dari aplikasi perpesanan dan aplikasi kolaborasi lainnya. Element beroperasi pada Matrix, jaringan terbuka untuk pengiriman pesan yang aman dan komunikasi terdesentralisasi. Element benar-benar berbeda dari aplikasi perpesanan dan aplikasi kolaborasi lainnya. Element beroperasi pada Matrix, jaringan terbuka untuk pengiriman pesan yang aman dan komunikasi yang terdesentralisasi.
<b>Perpesanan dengan privasi dan enkripsi</b> <b>Perpesanan dengan privasi dan enkripsi</b>
Element melindungi Anda dari iklan yang tidak diinginkan, penambangan data dan taman berdinding. Element juga mengamankan semua data Anda, komunikasi video dan suara satu-ke-satu dengan enkripsi ujung-ke-ujung dan verifikasi perangkat menggunakan penandatanganan silang. Element melindungi Anda dari iklan yang tidak diinginkan, penambangan data, dan taman berdinding. Element juga mengamankan semua data Anda, komunikasi video dan suara satu-ke-satu dengan enkripsi ujung-ke-ujung, dan verifikasi perangkat menggunakan penandatanganan silang.
Element memberikan Anda kendali atas privasi Anda sambil memungkinkan Anda untuk berkomunikasi dengan siapa saja secara aman di jaringan Matrix, atau alat kolaborasi bisnis lainnya dengan mengintegrasikan aplikasi-aplikasi seperti Slack. Element memberikan Anda kendali atas privasi Anda sambil memungkinkan Anda untuk berkomunikasi dengan siapa saja secara aman di jaringan Matrix, atau alat kolaborasi bisnis lainnya dengan mengintegrasikan aplikasi seperti Slack.
<b>Element dapat dihost sendiri</b> <b>Element dapat di-host sendiri</b>
Untuk memungkinkan lebih banyak kendali atas data dan pesan-pesan sensitif Anda, Element dapat dihost sendiri atau Anda dapat memilih host berbasis Matrix, standar untuk komunikasi terdesentralisasi sumber terbuka. Element memberi Anda privasi, kepatuhan keamanan, dan fleksibilitas integrasi. Untuk memungkinkan lebih banyak kendali atas data dan pesan-pesan sensitif Anda, Element dapat dilayani sendiri atau Anda dapat memilih layanan berbasis Matrix, standar untuk komunikasi terdesentralisasi sumber terbuka. Element memberikan Anda privasi, kepatuhan keamanan, dan fleksibilitas integrasi.
<b>Miliki data Anda</b> <b>Miliki data Anda</b>
Anda memutuskan di mana untuk menyimpan data dan pesan-pesan Anda, tanpa risiko penambangan data atau akses dari pihak ketiga. Anda memutuskan di mana untuk menyimpan data dan pesan-pesan Anda, tanpa risiko penambangan data atau akses dari pihak ketiga.
Element menempatkan Anda dalam kendali dengan cara yang berbeda: 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 1. Dapatkan akun gratis pada server publik matrix.org yang dilayani oleh pengembang Matrix, atau memilih dari ribuan server publik yang dilayani oleh sukarelawan
2. Host sendiri akun Anda dengan menjalankan server pada infrastruktur IT Anda sendiri 2. Layani akun Anda sendiri dengan menjalankan server pada infrastruktur IT Anda sendiri
3. Daftar untuk akun di server khusus dengan berlangganan platform hosting Layanan Matrix Element 3. Daftar untuk akun di server khusus dengan berlangganan platform hosting Layanan Matrix Element
<b>Perpesanan dan kolaborasi terbuka</b> <b>Perpesanan dan kolaborasi terbuka</b>
Anda dapat mengobrol dengan siapa saja di jaringan Matrix, jika mereka menggunakan Element, aplikasi Matrix lain atau bahkan menggunakan aplikasi perpesanan yang berbeda. Anda dapat mengobrol dengan siapa saja di jaringan Matrix, jika mereka menggunakan Element, aplikasi Matrix lain, atau bahkan menggunakan aplikasi perpesanan yang berbeda.
<b>Sangat aman</b> <b>Sangat aman</b>
Enkripsi ujung-ke-ujung yang nyata (hanya mereka yang dalam obrolan dapat mendekripsi pesan), dan verifikasi perangkat menggunakan penandatanganan silang. Enkripsi ujung-ke-ujung yang nyata (hanya mereka yang di dalam obrolan dapat mendekripsikan pesan), dan verifikasi perangkat menggunakan penandatanganan silang.
<b>Komunikasi dan integrasi lengkap</b> <b>Komunikasi dan integrasi lengkap</b>
Perpesanan, panggilan suara dan video, pembagian file, pembagian layar dan banyak integrasi bot dan widget. Buat ruangan dan komunitas, tetap terhubung dan selesaikan hal-hal penting. Perpesanan, panggilan suara dan video, pembagian berkas, pembagian layar dan banyak integrasi bot dan widget. Buat ruangan dan komunitas, tetap terhubung, dan selesaikan hal-hal penting.
<b>Ambil di mana Anda tinggalkan</b> <b>Ambil di mana Anda tinggalkan</b>
Tetap terhubung di mana Anda berada, dengan riwayat pesan yang disinkronkan di semua perangkat Anda dan web di https://app.element.io Tetap terhubung di mana Anda berada, dengan riwayat pesan yang disinkronkan pada semua perangkat Anda dan pada web di https://app.element.io
<b>Sumber terbuka</b> <b>Sumber terbuka</b>
Element Android adalah proyek sumber terbuka, dihost oleh GitHub. Silakan laporkan masalah yang Anda temukan, atau membuat kontribusi ke pengembangannya di https://github.com/vector-im/element-android Element Android adalah proyek sumber terbuka, dilayani oleh GitHub. Silakan laporkan masalah yang Anda temukan, atau membuat kontribusi ke pengembangannya di https://github.com/vector-im/element-android

View file

@ -0,0 +1,2 @@
Modifiche principali in questa versione: introduce i percorsi migliorati di accesso e registrazione.
Cronologia completa: https://github.com/vector-im/element-android/releases

View file

@ -0,0 +1,2 @@
Modifiche principali in questa versione: introduce i percorsi migliorati di accesso e registrazione.
Cronologia completa: https://github.com/vector-im/element-android/releases

View file

@ -0,0 +1,2 @@
Principais mudanças nesta versão: Habilita as jornadas melhoradas de sign in e sign up.
Changelog completo: https://github.com/vector-im/element-android/releases

View file

@ -0,0 +1,2 @@
Principais mudanças nesta versão: Habilita as jornadas melhoradas de sign in e sign up.
Changelog completo: https://github.com/vector-im/element-android/releases

View file

@ -0,0 +1,2 @@
Hlavné zmeny v tejto verzii: Umožňuje vylepšené postupy prihlasovania a registrácie.
Úplný zoznam zmien: https://github.com/vector-im/element-android/releases

View file

@ -0,0 +1,2 @@
Hlavné zmeny v tejto verzii: Umožňuje vylepšené postupy prihlasovania a registrácie.
Úplný zoznam zmien: https://github.com/vector-im/element-android/releases

View file

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

View file

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

View file

@ -0,0 +1,2 @@
此版本中的主要變動:啟用改善的登入與註冊流程。
完整的變更紀錄https://github.com/vector-im/element-android/releases

View file

@ -0,0 +1,2 @@
此版本中的主要變動:啟用改善的登入與註冊流程。
完整的變更紀錄https://github.com/vector-im/element-android/releases

View file

@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionSha256Sum=97a52d145762adc241bad7fd18289bf7f6801e08ece6badf80402fe2b9f250b1 distributionSha256Sum=db9c8211ed63f61f60292c69e80d89196f9eb36665e369e7f00ac4cc841c2219
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-all.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="DevicesListHeaderView">
<attr name="devicesListHeaderTitle" format="string" />
<attr name="devicesListHeaderDescription" format="string" />
</declare-styleable>
</resources>

View file

@ -62,4 +62,8 @@
<item name="colorPrimary">?colorOnPrimary</item> <item name="colorPrimary">?colorOnPrimary</item>
</style> </style>
<style name="Widget.Vector.FloatingActionButton" parent="Widget.MaterialComponents.FloatingActionButton">
<item name="shapeAppearanceOverlay">@style/ShapeAppearanceOverlay.Material3.FloatingActionButton</item>
</style>
</resources> </resources>

View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="TextAppearance.Vector.Subtitle.Medium.DevicesManagement">
<item name="android:textColor">?vctr_content_primary</item>
</style>
<style name="TextAppearance.Vector.Body.DevicesManagement">
<item name="android:textColor">?vctr_content_secondary</item>
</style>
</resources>

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Widget.Vector.TabLayout" parent="Widget.MaterialComponents.TabLayout">
<item name="materialThemeOverlay">@style/ThemeOverlay.Vector.HomeFilterTabLayout</item>
<item name="tabTextAppearance">@style/TextAppearance.Vector.FilterTabTextAppearance</item>
</style>
<style name="TextAppearance.Vector.FilterTabTextAppearance" parent="TextAppearance.Vector.Subtitle">
<item name="textAllCaps">false</item>
</style>
<style name="ThemeOverlay.Vector.HomeFilterTabLayout" parent="Theme.Vector.Launcher">
<item name="colorSurface">?vctr_toolbar_background</item>
<item name="colorOnSurface">?vctr_content_secondary</item>
</style>
</resources>

View file

@ -17,7 +17,7 @@ buildscript {
} }
} }
dependencies { dependencies {
classpath "io.realm:realm-gradle-plugin:10.11.0" classpath "io.realm:realm-gradle-plugin:10.11.1"
} }
} }
@ -60,7 +60,7 @@ android {
// that the app's state is completely cleared between tests. // that the app's state is completely cleared between tests.
testInstrumentationRunnerArguments clearPackageData: 'true' testInstrumentationRunnerArguments clearPackageData: 'true'
buildConfigField "String", "SDK_VERSION", "\"1.4.32\"" buildConfigField "String", "SDK_VERSION", "\"1.4.34\""
buildConfigField "String", "GIT_SDK_REVISION", "\"${gitRevision()}\"" buildConfigField "String", "GIT_SDK_REVISION", "\"${gitRevision()}\""
buildConfigField "String", "GIT_SDK_REVISION_UNIX_DATE", "\"${gitRevisionUnixDate()}\"" buildConfigField "String", "GIT_SDK_REVISION_UNIX_DATE", "\"${gitRevisionUnixDate()}\""
@ -199,7 +199,7 @@ dependencies {
implementation libs.apache.commonsImaging implementation libs.apache.commonsImaging
// Phone number https://github.com/google/libphonenumber // Phone number https://github.com/google/libphonenumber
implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.53' implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.54'
testImplementation libs.tests.junit testImplementation libs.tests.junit
// Note: version sticks to 1.9.2 due to https://github.com/mockk/mockk/issues/281 // Note: version sticks to 1.9.2 due to https://github.com/mockk/mockk/issues/281

View file

@ -28,7 +28,7 @@ interface DebugService {
fun getAllRealmConfigurations(): List<RealmConfiguration> fun getAllRealmConfigurations(): List<RealmConfiguration>
/** /**
* Prints out info on DB size to logcat. * Get info on DB size.
*/ */
fun logDbUsageInfo() fun getDbUsageInfo(): String
} }

View file

@ -89,10 +89,14 @@ fun Throwable.isInvalidUIAAuth() = this is Failure.ServerError &&
fun Throwable.isHomeserverUnavailable() = this is Failure.NetworkConnection && fun Throwable.isHomeserverUnavailable() = this is Failure.NetworkConnection &&
this.ioException is UnknownHostException this.ioException is UnknownHostException
fun Throwable.isHomeserverConnectionError() = this is Failure.NetworkConnection
fun Throwable.isMissingEmailVerification() = this is Failure.ServerError && fun Throwable.isMissingEmailVerification() = this is Failure.ServerError &&
error.code == MatrixError.M_UNAUTHORIZED && error.code == MatrixError.M_UNAUTHORIZED &&
error.message == "Unable to get validated threepid" error.message == "Unable to get validated threepid"
fun Throwable.isUnrecognisedCertificate() = this is Failure.UnrecognizedCertificateFailure
/** /**
* Try to convert to a RegistrationFlowResponse. Return null in the cases it's not possible * Try to convert to a RegistrationFlowResponse. Return null in the cases it's not possible
*/ */

View file

@ -323,9 +323,9 @@ interface Session {
fun getUiaSsoFallbackUrl(authenticationSessionId: String): String fun getUiaSsoFallbackUrl(authenticationSessionId: String): String
/** /**
* Debug API, will print out info on DB size to logcat. * Debug API, will return info about the DB.
*/ */
fun logDbUsageInfo() fun getDbUsageInfo(): String
/** /**
* Debug API, return the list of all RealmConfiguration used by this session. * Debug API, return the list of all RealmConfiguration used by this session.

View file

@ -29,14 +29,12 @@ data class RoomGuestAccessContent(
// Required. Whether guests can join the room. One of: ["can_join", "forbidden"] // Required. Whether guests can join the room. One of: ["can_join", "forbidden"]
@Json(name = "guest_access") val guestAccessStr: String? = null @Json(name = "guest_access") val guestAccessStr: String? = null
) { ) {
val guestAccess: GuestAccess? = when (guestAccessStr) { val guestAccess: GuestAccess? = GuestAccess.values()
"can_join" -> GuestAccess.CanJoin .find { it.value == guestAccessStr }
"forbidden" -> GuestAccess.Forbidden ?: run {
else -> { Timber.w("Invalid value for GuestAccess: `$guestAccessStr`")
Timber.w("Invalid value for GuestAccess: `$guestAccessStr`") null
null }
}
}
} }
@JsonClass(generateAdapter = false) @JsonClass(generateAdapter = false)

View file

@ -23,30 +23,30 @@ import com.squareup.moshi.JsonClass
* Ref: https://matrix.org/docs/spec/client_server/latest#room-history-visibility * Ref: https://matrix.org/docs/spec/client_server/latest#room-history-visibility
*/ */
@JsonClass(generateAdapter = false) @JsonClass(generateAdapter = false)
enum class RoomHistoryVisibility { enum class RoomHistoryVisibility(val value: String) {
/** /**
* All events while this is the m.room.history_visibility value may be shared by any * All events while this is the m.room.history_visibility value may be shared by any
* participating homeserver with anyone, regardless of whether they have ever joined the room. * participating homeserver with anyone, regardless of whether they have ever joined the room.
*/ */
@Json(name = "world_readable") WORLD_READABLE, @Json(name = "world_readable") WORLD_READABLE("world_readable"),
/** /**
* Previous events are always accessible to newly joined members. All events in the * Previous events are always accessible to newly joined members. All events in the
* room are accessible, even those sent when the member was not a part of the room. * room are accessible, even those sent when the member was not a part of the room.
*/ */
@Json(name = "shared") SHARED, @Json(name = "shared") SHARED("shared"),
/** /**
* Events are accessible to newly joined members from the point they were invited onwards. * Events are accessible to newly joined members from the point they were invited onwards.
* Events stop being accessible when the member's state changes to something other than invite or join. * Events stop being accessible when the member's state changes to something other than invite or join.
*/ */
@Json(name = "invited") INVITED, @Json(name = "invited") INVITED("invited"),
/** /**
* Events are accessible to newly joined members from the point they joined the room onwards. * Events are accessible to newly joined members from the point they joined the room onwards.
* Events stop being accessible when the member's state changes to something other than join. * Events stop being accessible when the member's state changes to something other than join.
*/ */
@Json(name = "joined") JOINED @Json(name = "joined") JOINED("joined")
} }
/** /**

View file

@ -24,14 +24,10 @@ import timber.log.Timber
data class RoomHistoryVisibilityContent( data class RoomHistoryVisibilityContent(
@Json(name = "history_visibility") val historyVisibilityStr: String? = null @Json(name = "history_visibility") val historyVisibilityStr: String? = null
) { ) {
val historyVisibility: RoomHistoryVisibility? = when (historyVisibilityStr) { val historyVisibility: RoomHistoryVisibility? = RoomHistoryVisibility.values()
"world_readable" -> RoomHistoryVisibility.WORLD_READABLE .find { it.value == historyVisibilityStr }
"shared" -> RoomHistoryVisibility.SHARED ?: run {
"invited" -> RoomHistoryVisibility.INVITED Timber.w("Invalid value for RoomHistoryVisibility: `$historyVisibilityStr`")
"joined" -> RoomHistoryVisibility.JOINED null
else -> { }
Timber.w("Invalid value for RoomHistoryVisibility: `$historyVisibilityStr`")
null
}
}
} }

View file

@ -16,7 +16,6 @@
package org.matrix.android.sdk.api.session.room.model.create 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.EventType
import org.matrix.android.sdk.api.session.events.model.toContent 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.homeserver.HomeServerCapabilities
@ -30,7 +29,7 @@ interface RoomFeaturePreset {
fun updateRoomParams(params: CreateRoomParams) fun updateRoomParams(params: CreateRoomParams)
fun setupInitialStates(): List<Event>? fun setupInitialStates(): List<CreateRoomStateEvent>?
} }
class RestrictedRoomPreset(val homeServerCapabilities: HomeServerCapabilities, val restrictedList: List<RoomJoinRulesAllowEntry>) : RoomFeaturePreset { class RestrictedRoomPreset(val homeServerCapabilities: HomeServerCapabilities, val restrictedList: List<RoomJoinRulesAllowEntry>) : RoomFeaturePreset {
@ -41,9 +40,9 @@ class RestrictedRoomPreset(val homeServerCapabilities: HomeServerCapabilities, v
params.roomVersion = homeServerCapabilities.versionOverrideForFeature(HomeServerCapabilities.ROOM_CAP_RESTRICTED) params.roomVersion = homeServerCapabilities.versionOverrideForFeature(HomeServerCapabilities.ROOM_CAP_RESTRICTED)
} }
override fun setupInitialStates(): List<Event>? { override fun setupInitialStates(): List<CreateRoomStateEvent> {
return listOf( return listOf(
Event( CreateRoomStateEvent(
type = EventType.STATE_ROOM_JOIN_RULES, type = EventType.STATE_ROOM_JOIN_RULES,
stateKey = "", stateKey = "",
content = RoomJoinRulesContent( content = RoomJoinRulesContent(

View file

@ -22,7 +22,7 @@ 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.session.room.model.relation.RelationDefaultContent
/** /**
* Content of the state event of type * Content of the event of type
* [EventType.BEACON_LOCATION_DATA][org.matrix.android.sdk.api.session.events.model.EventType.BEACON_LOCATION_DATA] * [EventType.BEACON_LOCATION_DATA][org.matrix.android.sdk.api.session.events.model.EventType.BEACON_LOCATION_DATA]
* *
* It contains location data related to a live location share. * It contains location data related to a live location share.

View file

@ -53,6 +53,11 @@ interface SyncService {
*/ */
fun getSyncState(): SyncState fun getSyncState(): SyncState
/**
* This method returns true if the sync thread is alive, i.e. started.
*/
fun isSyncThreadAlive(): Boolean
/** /**
* This method allows to listen the sync state. * This method allows to listen the sync state.
* @return a [LiveData] of [SyncState]. * @return a [LiveData] of [SyncState].

View file

@ -76,12 +76,12 @@ internal class VerificationTransportToDevice(
.configureWith(SendToDeviceTask.Params(MessageType.MSGTYPE_VERIFICATION_REQUEST, contentMap)) { .configureWith(SendToDeviceTask.Params(MessageType.MSGTYPE_VERIFICATION_REQUEST, contentMap)) {
this.callback = object : MatrixCallback<Unit> { this.callback = object : MatrixCallback<Unit> {
override fun onSuccess(data: Unit) { override fun onSuccess(data: Unit) {
Timber.v("## verification [$tx.transactionId] send toDevice request success") Timber.v("## verification [${tx?.transactionId}] send toDevice request success")
callback.invoke(localId, validKeyReq) callback.invoke(localId, validKeyReq)
} }
override fun onFailure(failure: Throwable) { override fun onFailure(failure: Throwable) {
Timber.e("## verification [$tx.transactionId] failed to send toDevice request") Timber.e("## verification [${tx?.transactionId}] failed to send toDevice request")
} }
} }
} }
@ -103,12 +103,12 @@ internal class VerificationTransportToDevice(
.configureWith(SendToDeviceTask.Params(EventType.KEY_VERIFICATION_READY, contentMap)) { .configureWith(SendToDeviceTask.Params(EventType.KEY_VERIFICATION_READY, contentMap)) {
this.callback = object : MatrixCallback<Unit> { this.callback = object : MatrixCallback<Unit> {
override fun onSuccess(data: Unit) { override fun onSuccess(data: Unit) {
Timber.v("## verification [$tx.transactionId] send toDevice request success") Timber.v("## verification [${tx?.transactionId}] send toDevice request success")
callback?.invoke() callback?.invoke()
} }
override fun onFailure(failure: Throwable) { override fun onFailure(failure: Throwable) {
Timber.e("## verification [$tx.transactionId] failed to send toDevice request") Timber.e("## verification [${tx?.transactionId}] failed to send toDevice request")
} }
} }
} }
@ -136,7 +136,7 @@ internal class VerificationTransportToDevice(
.configureWith(SendToDeviceTask.Params(type, contentMap)) { .configureWith(SendToDeviceTask.Params(type, contentMap)) {
this.callback = object : MatrixCallback<Unit> { this.callback = object : MatrixCallback<Unit> {
override fun onSuccess(data: Unit) { override fun onSuccess(data: Unit) {
Timber.v("## SAS verification [$tx.transactionId] toDevice type '$type' success.") Timber.v("## SAS verification [${tx.transactionId}] toDevice type '$type' success.")
if (onDone != null) { if (onDone != null) {
onDone() onDone()
} else { } else {
@ -149,7 +149,7 @@ internal class VerificationTransportToDevice(
} }
override fun onFailure(failure: Throwable) { override fun onFailure(failure: Throwable) {
Timber.e("## SAS verification [$tx.transactionId] failed to send toDevice in state : $tx.state") Timber.e("## SAS verification [${tx.transactionId}] failed to send toDevice in state : ${tx.state}")
tx.cancel(onErrorReason) tx.cancel(onErrorReason)
} }
} }

View file

@ -0,0 +1,28 @@
/*
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.database
import io.realm.DefaultCompactOnLaunchCallback
class RealmCompactOnLaunch : DefaultCompactOnLaunchCallback() {
/**
* Forces all RealmCompactOnLaunch instances to be equal.
* Avoids Realm throwing when multiple instances of this class are used.
*/
override fun equals(other: Any?) = other is RealmCompactOnLaunch
override fun hashCode() = 0x1000
}

View file

@ -38,7 +38,7 @@ internal abstract class RealmLiveEntityObserver<T : RealmObject>(protected val r
LiveEntityObserver, RealmChangeListener<RealmResults<T>> { LiveEntityObserver, RealmChangeListener<RealmResults<T>> {
private companion object { private companion object {
val BACKGROUND_HANDLER = createBackgroundHandler("LIVE_ENTITY_BACKGROUND") val BACKGROUND_HANDLER = createBackgroundHandler("Matrix-LIVE_ENTITY_BACKGROUND")
} }
protected val observerScope = CoroutineScope(SupervisorJob() + BACKGROUND_HANDLER.asCoroutineDispatcher()) protected val observerScope = CoroutineScope(SupervisorJob() + BACKGROUND_HANDLER.asCoroutineDispatcher())

View file

@ -64,7 +64,7 @@ internal class SessionRealmConfigurationFactory @Inject constructor(
} }
val realmConfiguration = RealmConfiguration.Builder() val realmConfiguration = RealmConfiguration.Builder()
.compactOnLaunch() .compactOnLaunch(RealmCompactOnLaunch())
.directory(directory) .directory(directory)
.name(REALM_NAME) .name(REALM_NAME)
.apply { .apply {
@ -93,7 +93,7 @@ internal class SessionRealmConfigurationFactory @Inject constructor(
return return
} }
listOf(REALM_NAME, "$REALM_NAME.lock", "$REALM_NAME.note", "$REALM_NAME.management").forEach { file -> listOf(REALM_NAME, "${REALM_NAME}.lock", "${REALM_NAME}.note", "${REALM_NAME}.management").forEach { file ->
try { try {
File(directory, file).deleteRecursively() File(directory, file).deleteRecursively()
} catch (e: Exception) { } catch (e: Exception) {

View file

@ -19,16 +19,15 @@ package org.matrix.android.sdk.internal.database.tools
import io.realm.Realm import io.realm.Realm
import io.realm.RealmConfiguration import io.realm.RealmConfiguration
import org.matrix.android.sdk.BuildConfig import org.matrix.android.sdk.BuildConfig
import timber.log.Timber
internal class RealmDebugTools( internal class RealmDebugTools(
private val realmConfiguration: RealmConfiguration private val realmConfiguration: RealmConfiguration
) { ) {
/** /**
* Log info about the DB. * Get info about the DB.
*/ */
fun logInfo(baseName: String) { fun getInfo(baseName: String): String {
buildString { return buildString {
append("\n$baseName Realm located at : ${realmConfiguration.realmDirectory}/${realmConfiguration.realmFileName}") append("\n$baseName Realm located at : ${realmConfiguration.realmDirectory}/${realmConfiguration.realmFileName}")
if (BuildConfig.LOG_PRIVATE_DATA) { if (BuildConfig.LOG_PRIVATE_DATA) {
@ -54,7 +53,6 @@ internal class RealmDebugTools(
separator() separator()
} }
} }
.let { Timber.i(it) }
} }
private fun StringBuilder.separator() = append("\n==============================================") private fun StringBuilder.separator() = append("\n==============================================")

View file

@ -36,9 +36,9 @@ internal class DefaultDebugService @Inject constructor(
realmConfigurationGlobal realmConfigurationGlobal
} }
override fun logDbUsageInfo() { override fun getDbUsageInfo() = buildString {
RealmDebugTools(realmConfigurationAuth).logInfo("Auth") append(RealmDebugTools(realmConfigurationAuth).getInfo("Auth"))
RealmDebugTools(realmConfigurationGlobal).logInfo("Global") append(RealmDebugTools(realmConfigurationGlobal).getInfo("Global"))
sessionManager.getLastSession()?.logDbUsageInfo() append(sessionManager.getLastSession()?.getDbUsageInfo())
} }
} }

View file

@ -40,7 +40,7 @@ internal object MatrixModule {
io = Dispatchers.IO, io = Dispatchers.IO,
computation = Dispatchers.Default, computation = Dispatchers.Default,
main = Dispatchers.Main, main = Dispatchers.Main,
crypto = createBackgroundHandler("Crypto_Thread").asCoroutineDispatcher(), crypto = createBackgroundHandler("Matrix-Crypto_Thread").asCoroutineDispatcher(),
dmVerif = Executors.newSingleThreadExecutor().asCoroutineDispatcher() dmVerif = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
) )
} }

View file

@ -263,11 +263,11 @@ internal class DefaultSession @Inject constructor(
} }
} }
override fun logDbUsageInfo() { override fun getDbUsageInfo() = buildString {
RealmDebugTools(realmConfiguration).logInfo("Session") append(RealmDebugTools(realmConfiguration).getInfo("Session"))
RealmDebugTools(realmConfigurationCrypto).logInfo("Crypto") append(RealmDebugTools(realmConfigurationCrypto).getInfo("Crypto"))
RealmDebugTools(realmConfigurationIdentity).logInfo("Identity") append(RealmDebugTools(realmConfigurationIdentity).getInfo("Identity"))
RealmDebugTools(realmConfigurationContentScanner).logInfo("ContentScanner") append(RealmDebugTools(realmConfigurationContentScanner).getInfo("ContentScanner"))
} }
override fun getRealmConfigurations(): List<RealmConfiguration> { override fun getRealmConfigurations(): List<RealmConfiguration> {

View file

@ -20,8 +20,13 @@ import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM
import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.session.events.model.Event 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.EventType
import org.matrix.android.sdk.api.session.events.model.content.EncryptionEventContent
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.IdentityServiceError
import org.matrix.android.sdk.api.session.identity.toMedium import org.matrix.android.sdk.api.session.identity.toMedium
import org.matrix.android.sdk.api.session.room.model.RoomAvatarContent
import org.matrix.android.sdk.api.session.room.model.RoomGuestAccessContent
import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibilityContent
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
import org.matrix.android.sdk.api.util.MimeTypes import org.matrix.android.sdk.api.util.MimeTypes
import org.matrix.android.sdk.internal.crypto.DeviceListManager import org.matrix.android.sdk.internal.crypto.DeviceListManager
@ -78,7 +83,7 @@ internal class CreateRoomBodyBuilder @Inject constructor(
buildAvatarEvent(params), buildAvatarEvent(params),
buildGuestAccess(params) buildGuestAccess(params)
) + ) +
params.featurePreset?.setupInitialStates().orEmpty() + buildFeaturePresetInitialStates(params) +
buildCustomInitialStates(params) buildCustomInitialStates(params)
) )
.takeIf { it.isNotEmpty() } .takeIf { it.isNotEmpty() }
@ -99,6 +104,16 @@ internal class CreateRoomBodyBuilder @Inject constructor(
) )
} }
private fun buildFeaturePresetInitialStates(params: CreateRoomParams): List<Event> {
return params.featurePreset?.setupInitialStates().orEmpty().map {
Event(
type = it.type,
stateKey = it.stateKey,
content = it.content
)
}
}
private fun buildCustomInitialStates(params: CreateRoomParams): List<Event> { private fun buildCustomInitialStates(params: CreateRoomParams): List<Event> {
return params.initialStates.map { return params.initialStates.map {
Event( Event(
@ -123,7 +138,7 @@ internal class CreateRoomBodyBuilder @Inject constructor(
Event( Event(
type = EventType.STATE_ROOM_AVATAR, type = EventType.STATE_ROOM_AVATAR,
stateKey = "", stateKey = "",
content = mapOf("url" to response.contentUri) content = RoomAvatarContent(response.contentUri).toContent()
) )
} }
} }
@ -134,7 +149,7 @@ internal class CreateRoomBodyBuilder @Inject constructor(
Event( Event(
type = EventType.STATE_ROOM_HISTORY_VISIBILITY, type = EventType.STATE_ROOM_HISTORY_VISIBILITY,
stateKey = "", stateKey = "",
content = mapOf("history_visibility" to it) content = RoomHistoryVisibilityContent(it.value).toContent()
) )
} }
} }
@ -145,7 +160,7 @@ internal class CreateRoomBodyBuilder @Inject constructor(
Event( Event(
type = EventType.STATE_ROOM_GUEST_ACCESS, type = EventType.STATE_ROOM_GUEST_ACCESS,
stateKey = "", stateKey = "",
content = mapOf("guest_access" to it.value) content = RoomGuestAccessContent(it.value).toContent()
) )
} }
} }
@ -167,7 +182,7 @@ internal class CreateRoomBodyBuilder @Inject constructor(
Event( Event(
type = EventType.STATE_ROOM_ENCRYPTION, type = EventType.STATE_ROOM_ENCRYPTION,
stateKey = "", stateKey = "",
content = mapOf("algorithm" to it) content = EncryptionEventContent(it).toContent()
) )
} }
} }

View file

@ -53,7 +53,7 @@ internal class MultipleEventSendingDispatcherWorker(context: Context, params: Wo
@Inject lateinit var timelineSendEventWorkCommon: TimelineSendEventWorkCommon @Inject lateinit var timelineSendEventWorkCommon: TimelineSendEventWorkCommon
@Inject lateinit var localEchoRepository: LocalEchoRepository @Inject lateinit var localEchoRepository: LocalEchoRepository
override fun doOnError(params: Params): Result { override fun doOnError(params: Params, failureMessage: String): Result {
params.localEchoIds.forEach { localEchoIds -> params.localEchoIds.forEach { localEchoIds ->
localEchoRepository.updateSendState( localEchoRepository.updateSendState(
eventId = localEchoIds.eventId, eventId = localEchoIds.eventId,
@ -63,7 +63,7 @@ internal class MultipleEventSendingDispatcherWorker(context: Context, params: Wo
) )
} }
return super.doOnError(params) return super.doOnError(params, failureMessage)
} }
override fun injectWith(injector: SessionComponent) { override fun injectWith(injector: SessionComponent) {

View file

@ -55,7 +55,7 @@ internal class EventSenderProcessorThread @Inject constructor(
private val queuedTaskFactory: QueuedTaskFactory, private val queuedTaskFactory: QueuedTaskFactory,
private val taskExecutor: TaskExecutor, private val taskExecutor: TaskExecutor,
private val memento: QueueMemento private val memento: QueueMemento
) : Thread("SENDER_THREAD_SID_${sessionParams.credentials.sessionId()}"), EventSenderProcessor { ) : Thread("Matrix-SENDER_THREAD_SID_${sessionParams.credentials.sessionId()}"), EventSenderProcessor {
private fun markAsManaged(task: QueuedTask) { private fun markAsManaged(task: QueuedTask) {
memento.track(task) memento.track(task)

View file

@ -80,7 +80,7 @@ internal class DefaultTimeline(
) : Timeline { ) : Timeline {
companion object { companion object {
val BACKGROUND_HANDLER = createBackgroundHandler("DefaultTimeline_Thread") val BACKGROUND_HANDLER = createBackgroundHandler("Matrix-DefaultTimeline_Thread")
} }
override val timelineID = UUID.randomUUID().toString() override val timelineID = UUID.randomUUID().toString()

View file

@ -73,6 +73,8 @@ internal class DefaultSyncService @Inject constructor(
override fun getSyncState() = getSyncThread().currentState() override fun getSyncState() = getSyncThread().currentState()
override fun isSyncThreadAlive() = getSyncThread().isAlive
override fun getSyncRequestStateFlow() = syncRequestStateTracker.syncRequestState override fun getSyncRequestStateFlow() = syncRequestStateTracker.syncRequestState
override fun hasAlreadySynced(): Boolean { override fun hasAlreadySynced(): Boolean {

View file

@ -62,7 +62,7 @@ internal class SyncThread @Inject constructor(
private val backgroundDetectionObserver: BackgroundDetectionObserver, private val backgroundDetectionObserver: BackgroundDetectionObserver,
private val activeCallHandler: ActiveCallHandler, private val activeCallHandler: ActiveCallHandler,
private val lightweightSettingsStorage: DefaultLightweightSettingsStorage private val lightweightSettingsStorage: DefaultLightweightSettingsStorage
) : Thread("SyncThread"), NetworkConnectivityChecker.Listener, BackgroundDetectionObserver.Listener { ) : Thread("Matrix-SyncThread"), NetworkConnectivityChecker.Listener, BackgroundDetectionObserver.Listener {
private var state: SyncState = SyncState.Idle private var state: SyncState = SyncState.Idle
private var liveState = MutableLiveData(state) private var liveState = MutableLiveData(state)

View file

@ -30,6 +30,7 @@ import org.matrix.android.sdk.internal.session.sync.SyncTask
import org.matrix.android.sdk.internal.worker.SessionSafeCoroutineWorker import org.matrix.android.sdk.internal.worker.SessionSafeCoroutineWorker
import org.matrix.android.sdk.internal.worker.SessionWorkerParams import org.matrix.android.sdk.internal.worker.SessionWorkerParams
import org.matrix.android.sdk.internal.worker.WorkerParamsFactory import org.matrix.android.sdk.internal.worker.WorkerParamsFactory
import org.matrix.android.sdk.internal.worker.startChain
import timber.log.Timber import timber.log.Timber
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import javax.inject.Inject import javax.inject.Inject
@ -136,6 +137,7 @@ internal class SyncWorker(context: Context, workerParameters: WorkerParameters,
.setConstraints(WorkManagerProvider.workConstraints) .setConstraints(WorkManagerProvider.workConstraints)
.setBackoffCriteria(BackoffPolicy.LINEAR, WorkManagerProvider.BACKOFF_DELAY_MILLIS, TimeUnit.MILLISECONDS) .setBackoffCriteria(BackoffPolicy.LINEAR, WorkManagerProvider.BACKOFF_DELAY_MILLIS, TimeUnit.MILLISECONDS)
.setInputData(data) .setInputData(data)
.startChain(true)
.build() .build()
workManagerProvider.workManager workManagerProvider.workManager
.enqueueUniqueWork(BG_SYNC_WORK_NAME, ExistingWorkPolicy.APPEND_OR_REPLACE, workRequest) .enqueueUniqueWork(BG_SYNC_WORK_NAME, ExistingWorkPolicy.APPEND_OR_REPLACE, workRequest)

View file

@ -49,13 +49,13 @@ internal class DefaultBackgroundDetectionObserver : BackgroundDetectionObserver
} }
override fun onStart(owner: LifecycleOwner) { override fun onStart(owner: LifecycleOwner) {
Timber.v("App returning to foreground…") Timber.d("App returning to foreground…")
isInBackground = false isInBackground = false
listeners.forEach { it.onMoveToForeground() } listeners.forEach { it.onMoveToForeground() }
} }
override fun onStop(owner: LifecycleOwner) { override fun onStop(owner: LifecycleOwner) {
Timber.v("App going to background…") Timber.d("App going to background…")
isInBackground = true isInBackground = true
listeners.forEach { it.onMoveToBackground() } listeners.forEach { it.onMoveToBackground() }
} }

View file

@ -55,14 +55,16 @@ internal abstract class SessionSafeCoroutineWorker<PARAM : SessionWorkerParams>(
// Make sure to inject before handling error as you may need some dependencies to process them. // Make sure to inject before handling error as you may need some dependencies to process them.
injectWith(sessionComponent) injectWith(sessionComponent)
if (params.lastFailureMessage != null) {
// Forward error to the next workers when (val lastFailureMessage = params.lastFailureMessage) {
doOnError(params) null -> doSafeWork(params)
} else { else -> {
doSafeWork(params) // Forward error to the next workers
doOnError(params, lastFailureMessage)
}
} }
} catch (throwable: Throwable) { } catch (throwable: Throwable) {
buildErrorResult(params, throwable.localizedMessage ?: "error") buildErrorResult(params, "${throwable::class.java.name}: ${throwable.localizedMessage ?: "N/A error message"}")
} }
} }
@ -89,10 +91,10 @@ internal abstract class SessionSafeCoroutineWorker<PARAM : SessionWorkerParams>(
* This is called when the input parameters are correct, but contain an error from the previous worker. * This is called when the input parameters are correct, but contain an error from the previous worker.
*/ */
@CallSuper @CallSuper
open fun doOnError(params: PARAM): Result { open fun doOnError(params: PARAM, failureMessage: String): Result {
// Forward the error // Forward the error
return Result.success(inputData) return Result.success(inputData)
.also { Timber.e("Work cancelled due to input error from parent") } .also { Timber.e("Work cancelled due to input error from parent: $failureMessage") }
} }
companion object { companion object {

View file

@ -16,21 +16,6 @@
# limitations under the License. # limitations under the License.
# #
#######################################################################################################################
# Check frozen class modification
#######################################################################################################################
echo "Check if frozen class modified"
git diff "HEAD@{1}" --name-only | grep -e OlmInboundGroupSessionWrapper.kt -e OlmInboundGroupSessionWrapper2.kt
FROZEN_CHANGED=$?
if [ ${FROZEN_CHANGED} -eq 0 ]; then
echo "❌ FROZEN CLASS CHANGED ERROR"
exit 1
else
echo "Frozen check OK"
fi
####################################################################################################################### #######################################################################################################################
# Check drawable quantity # Check drawable quantity
####################################################################################################################### #######################################################################################################################

View file

@ -185,3 +185,6 @@ System\.currentTimeMillis\(\)===2
onCreateOptionsMenu onCreateOptionsMenu
onOptionsItemSelected onOptionsItemSelected
onPrepareOptionsMenu onPrepareOptionsMenu
### Suspicious String template. Please check that the string template will behave as expected, i.e. the class field and not the whole object will be used. For instance `Timber.d("$event.type")` is not correct, you should write `Timber.d("${event.type}")`. In the former the whole event content will be logged, since it's a data class. If this is expected (i.e. to fix false positive), please add explicit curly braces (`{` and `}`) around the variable, for instance `"elementLogs.${i}.txt"`
\$[a-zA-Z_]\w*\??\.[a-zA-Z_]

View file

@ -52,6 +52,19 @@ if (requiresChangelog) {
} }
} }
// check that frozen classes have not been modified
const frozenClasses = [
"OlmInboundGroupSessionWrapper.kt",
"OlmInboundGroupSessionWrapper2.kt",
]
frozenClasses.forEach(frozen => {
if (editedFiles.some(file => file.endsWith(frozen))) {
fail("Frozen class `" + frozen + "` has been modified. Please do not modify frozen class.")
}
}
)
// Check for a sign-off // Check for a sign-off
const signOff = "Signed-off-by:" const signOff = "Signed-off-by:"

View file

@ -2634,7 +2634,8 @@
"mask", "mask",
"sick", "sick",
"ill", "ill",
"disease" "disease",
"covid"
] ]
}, },
"face-with-thermometer": { "face-with-thermometer": {
@ -2647,7 +2648,8 @@
"thermometer", "thermometer",
"temperature", "temperature",
"cold", "cold",
"fever" "fever",
"covid"
] ]
}, },
"face-with-headbandage": { "face-with-headbandage": {
@ -4481,7 +4483,9 @@
"hope", "hope",
"wish", "wish",
"namaste", "namaste",
"highfive" "highfive",
"thank you",
"appreciate"
] ]
}, },
"writing-hand": { "writing-hand": {
@ -9581,7 +9585,8 @@
"amoeba", "amoeba",
"bacteria", "bacteria",
"virus", "virus",
"germs" "germs",
"covid"
] ]
}, },
"bouquet": { "bouquet": {
@ -10260,7 +10265,9 @@
"baguette", "baguette",
"bread", "bread",
"food", "food",
"french" "french",
"france",
"bakery"
] ]
}, },
"flatbread": { "flatbread": {
@ -10272,7 +10279,8 @@
"naan", "naan",
"pita", "pita",
"flour", "flour",
"food" "food",
"bakery"
] ]
}, },
"pretzel": { "pretzel": {
@ -10282,7 +10290,9 @@
"twisted", "twisted",
"convoluted", "convoluted",
"food", "food",
"bread" "bread",
"germany",
"bakery"
] ]
}, },
"bagel": { "bagel": {
@ -10293,7 +10303,8 @@
"breakfast", "breakfast",
"schmear", "schmear",
"food", "food",
"bread" "bread",
"jewish"
] ]
}, },
"pancakes": { "pancakes": {
@ -10306,7 +10317,8 @@
"hotcake", "hotcake",
"pancake", "pancake",
"flapjacks", "flapjacks",
"hotcakes" "hotcakes",
"brunch"
] ]
}, },
"waffle": { "waffle": {
@ -10316,7 +10328,8 @@
"breakfast", "breakfast",
"indecisive", "indecisive",
"iron", "iron",
"food" "food",
"brunch"
] ]
}, },
"cheese-wedge": { "cheese-wedge": {
@ -10325,7 +10338,8 @@
"j": [ "j": [
"cheese", "cheese",
"food", "food",
"chadder" "chadder",
"swiss"
] ]
}, },
"meat-on-bone": { "meat-on-bone": {
@ -10376,7 +10390,8 @@
"food", "food",
"meat", "meat",
"pork", "pork",
"pig" "pig",
"brunch"
] ]
}, },
"hamburger": { "hamburger": {
@ -10400,7 +10415,8 @@
"fries", "fries",
"chips", "chips",
"snack", "snack",
"fast food" "fast food",
"potato"
] ]
}, },
"pizza": { "pizza": {
@ -10410,7 +10426,8 @@
"cheese", "cheese",
"slice", "slice",
"food", "food",
"party" "party",
"italy"
] ]
}, },
"hot-dog": { "hot-dog": {
@ -10420,7 +10437,8 @@
"frankfurter", "frankfurter",
"hotdog", "hotdog",
"sausage", "sausage",
"food" "food",
"america"
] ]
}, },
"sandwich": { "sandwich": {
@ -10429,7 +10447,9 @@
"j": [ "j": [
"bread", "bread",
"food", "food",
"lunch" "lunch",
"toast",
"bakery"
] ]
}, },
"taco": { "taco": {
@ -10468,7 +10488,8 @@
"food", "food",
"gyro", "gyro",
"kebab", "kebab",
"stuffed" "stuffed",
"mediterranean"
] ]
}, },
"falafel": { "falafel": {
@ -10477,7 +10498,8 @@
"j": [ "j": [
"chickpea", "chickpea",
"meatball", "meatball",
"food" "food",
"mediterranean"
] ]
}, },
"egg": { "egg": {
@ -10498,7 +10520,8 @@
"frying", "frying",
"pan", "pan",
"food", "food",
"kitchen" "kitchen",
"skillet"
] ]
}, },
"shallow-pan-of-food": { "shallow-pan-of-food": {
@ -10510,7 +10533,8 @@
"paella", "paella",
"pan", "pan",
"shallow", "shallow",
"cooking" "cooking",
"skillet"
] ]
}, },
"pot-of-food": { "pot-of-food": {
@ -10521,7 +10545,8 @@
"stew", "stew",
"food", "food",
"meat", "meat",
"soup" "soup",
"hot pot"
] ]
}, },
"fondue": { "fondue": {
@ -10556,7 +10581,8 @@
"green", "green",
"salad", "salad",
"healthy", "healthy",
"lettuce" "lettuce",
"vegetable"
] ]
}, },
"popcorn": { "popcorn": {
@ -10566,7 +10592,8 @@
"food", "food",
"movie theater", "movie theater",
"films", "films",
"snack" "snack",
"drama"
] ]
}, },
"butter": { "butter": {
@ -10592,7 +10619,8 @@
"j": [ "j": [
"can", "can",
"food", "food",
"soup" "soup",
"tomatoes"
] ]
}, },
"bento-box": { "bento-box": {
@ -10602,7 +10630,8 @@
"bento", "bento",
"box", "box",
"food", "food",
"japanese" "japanese",
"lunch"
] ]
}, },
"rice-cracker": { "rice-cracker": {
@ -10612,7 +10641,8 @@
"cracker", "cracker",
"rice", "rice",
"food", "food",
"japanese" "japanese",
"snack"
] ]
}, },
"rice-ball": { "rice-ball": {
@ -10633,7 +10663,6 @@
"cooked", "cooked",
"rice", "rice",
"food", "food",
"china",
"asian" "asian"
] ]
}, },
@ -10680,7 +10709,8 @@
"roasted", "roasted",
"sweet", "sweet",
"food", "food",
"nature" "nature",
"plant"
] ]
}, },
"oden": { "oden": {
@ -10745,7 +10775,8 @@
"autumn", "autumn",
"festival", "festival",
"yuèbǐng", "yuèbǐng",
"food" "food",
"dessert"
] ]
}, },
"dango": { "dango": {
@ -10772,7 +10803,8 @@
"jiaozi", "jiaozi",
"pierogi", "pierogi",
"potsticker", "potsticker",
"food" "food",
"gyoza"
] ]
}, },
"fortune-cookie": { "fortune-cookie": {
@ -10780,7 +10812,8 @@
"b": "1F960", "b": "1F960",
"j": [ "j": [
"prophecy", "prophecy",
"food" "food",
"dessert"
] ]
}, },
"takeout-box": { "takeout-box": {
@ -22169,7 +22202,9 @@
"nation", "nation",
"country", "country",
"banner", "banner",
"japan" "japan",
"jp",
"ja"
] ]
}, },
"flag-kenya": { "flag-kenya": {

View file

@ -18,6 +18,5 @@ package im.vector.app.config
enum class OnboardingVariant { enum class OnboardingVariant {
LEGACY, LEGACY,
LOGIN_2,
FTUE_AUTH FTUE_AUTH
} }

View file

@ -37,7 +37,7 @@ ext.versionMinor = 4
// Note: even values are reserved for regular release, odd values for hotfix release. // Note: even values are reserved for regular release, odd values for hotfix release.
// When creating a hotfix, you should decrease the value, since the current value // When creating a hotfix, you should decrease the value, since the current value
// is the value for the next regular release. // is the value for the next regular release.
ext.versionPatch = 32 ext.versionPatch = 34
ext.scVersion = 57 ext.scVersion = 57
@ -312,7 +312,6 @@ android {
versionName "1.4.32.sc57" versionName "1.4.32.sc57"
resValue "bool", "isGplay", "true"
buildConfigField "String", "SHORT_FLAVOR_DESCRIPTION", "\"G\"" buildConfigField "String", "SHORT_FLAVOR_DESCRIPTION", "\"G\""
buildConfigField "String", "FLAVOR_DESCRIPTION", "\"GooglePlay\"" buildConfigField "String", "FLAVOR_DESCRIPTION", "\"GooglePlay\""
} }
@ -322,7 +321,6 @@ android {
versionName "1.4.32.sc57" versionName "1.4.32.sc57"
resValue "bool", "isGplay", "false"
buildConfigField "String", "SHORT_FLAVOR_DESCRIPTION", "\"F\"" buildConfigField "String", "SHORT_FLAVOR_DESCRIPTION", "\"F\""
buildConfigField "String", "FLAVOR_DESCRIPTION", "\"FDroid\"" buildConfigField "String", "FLAVOR_DESCRIPTION", "\"FDroid\""
} }
@ -403,7 +401,7 @@ dependencies {
implementation libs.androidx.biometric implementation libs.androidx.biometric
implementation "org.threeten:threetenbp:1.4.0:no-tzdb" implementation "org.threeten:threetenbp:1.4.0:no-tzdb"
implementation "com.gabrielittner.threetenbp:lazythreetenbp:0.10.0" implementation "com.gabrielittner.threetenbp:lazythreetenbp:0.11.0"
implementation libs.squareup.moshi implementation libs.squareup.moshi
implementation libs.squareup.moshiKt implementation libs.squareup.moshiKt
@ -426,7 +424,7 @@ dependencies {
implementation 'com.facebook.stetho:stetho:1.6.0' implementation 'com.facebook.stetho:stetho:1.6.0'
// Phone number https://github.com/google/libphonenumber // Phone number https://github.com/google/libphonenumber
implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.53' implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.54'
// FlowBinding // FlowBinding
implementation libs.github.flowBinding implementation libs.github.flowBinding
@ -514,7 +512,7 @@ dependencies {
implementation 'com.posthog.android:posthog:1.1.2' implementation 'com.posthog.android:posthog:1.1.2'
// UnifiedPush // UnifiedPush
implementation 'com.github.UnifiedPush:android-connector:2.0.0' implementation 'com.github.UnifiedPush:android-connector:2.0.1'
// UnifiedPush gplay flavor only // UnifiedPush gplay flavor only
gplayImplementation('com.github.UnifiedPush:android-embedded_fcm_distributor:2.1.1') { gplayImplementation('com.github.UnifiedPush:android-embedded_fcm_distributor:2.1.1') {
exclude group: 'com.google.firebase', module: 'firebase-core' exclude group: 'com.google.firebase', module: 'firebase-core'
@ -590,7 +588,7 @@ dependencies {
debugImplementation "com.kgurgul.flipper:flipper-realm-android:2.2.0" debugImplementation "com.kgurgul.flipper:flipper-realm-android:2.2.0"
// Activate when you want to check for leaks, from time to time. // Activate when you want to check for leaks, from time to time.
//debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.3' debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.9.1'
androidTestImplementation libs.androidx.testCore androidTestImplementation libs.androidx.testCore
androidTestImplementation libs.androidx.testRunner androidTestImplementation libs.androidx.testRunner

View file

@ -83,7 +83,7 @@ private fun useMediaStoreScreenshotStorage(
screenshotLocation: String, screenshotLocation: String,
bitmap: Bitmap bitmap: Bitmap
) { ) {
contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, "$screenshotName.jpeg") contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, "${screenshotName}.jpeg")
contentValues.put(MediaStore.Images.Media.RELATIVE_PATH, screenshotLocation) contentValues.put(MediaStore.Images.Media.RELATIVE_PATH, screenshotLocation)
val uri: Uri? = contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues) val uri: Uri? = contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
if (uri != null) { if (uri != null) {
@ -104,7 +104,7 @@ private fun usePublicExternalScreenshotStorage(
if (!directory.exists()) { if (!directory.exists()) {
directory.mkdirs() directory.mkdirs()
} }
val file = File(directory, "$screenshotName.jpeg") val file = File(directory, "${screenshotName}.jpeg")
saveScreenshotToStream(bitmap, FileOutputStream(file)) saveScreenshotToStream(bitmap, FileOutputStream(file))
contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues) contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
} }

View file

@ -76,7 +76,7 @@ class EmojiDataSourceTest : InstrumentedTest {
fun searchTestOneResult() { fun searchTestOneResult() {
val emojiDataSource = createEmojiDataSource() val emojiDataSource = createEmojiDataSource()
val result = runBlocking { val result = runBlocking {
emojiDataSource.filterWith("france") emojiDataSource.filterWith("flag-france")
} }
assertEquals("Should have 1 result", 1, result.size) assertEquals("Should have 1 result", 1, result.size)
} }

View file

@ -9,6 +9,8 @@
<activity android:name=".features.debug.settings.DebugPrivateSettingsActivity" /> <activity android:name=".features.debug.settings.DebugPrivateSettingsActivity" />
<activity android:name=".features.debug.sas.DebugSasEmojiActivity" /> <activity android:name=".features.debug.sas.DebugSasEmojiActivity" />
<activity android:name=".features.debug.features.DebugFeaturesSettingsActivity" /> <activity android:name=".features.debug.features.DebugFeaturesSettingsActivity" />
<activity android:name=".features.debug.DebugMenuActivity" />
<activity android:name=".features.debug.leak.DebugMemoryLeaksActivity" />
<activity <activity
android:name="com.facebook.flipper.android.diagnostics.FlipperDiagnosticActivity" android:name="com.facebook.flipper.android.diagnostics.FlipperDiagnosticActivity"

View file

@ -37,6 +37,7 @@ import im.vector.app.core.utils.toast
import im.vector.app.databinding.ActivityDebugMenuBinding import im.vector.app.databinding.ActivityDebugMenuBinding
import im.vector.app.features.debug.analytics.DebugAnalyticsActivity import im.vector.app.features.debug.analytics.DebugAnalyticsActivity
import im.vector.app.features.debug.features.DebugFeaturesSettingsActivity import im.vector.app.features.debug.features.DebugFeaturesSettingsActivity
import im.vector.app.features.debug.leak.DebugMemoryLeaksActivity
import im.vector.app.features.debug.sas.DebugSasEmojiActivity import im.vector.app.features.debug.sas.DebugSasEmojiActivity
import im.vector.app.features.debug.settings.DebugPrivateSettingsActivity import im.vector.app.features.debug.settings.DebugPrivateSettingsActivity
import im.vector.app.features.qrcode.QrCodeScannerActivity import im.vector.app.features.qrcode.QrCodeScannerActivity
@ -86,6 +87,7 @@ class DebugMenuActivity : VectorBaseActivity<ActivityDebugMenuBinding>() {
views.debugAnalytics.setOnClickListener { views.debugAnalytics.setOnClickListener {
startActivity(Intent(this, DebugAnalyticsActivity::class.java)) startActivity(Intent(this, DebugAnalyticsActivity::class.java))
} }
views.debugMemoryLeaks.setOnClickListener { openMemoryLeaksSettings() }
views.debugTestTextViewLink.setOnClickListener { testTextViewLink() } views.debugTestTextViewLink.setOnClickListener { testTextViewLink() }
views.debugOpenButtonStylesLight.setOnClickListener { views.debugOpenButtonStylesLight.setOnClickListener {
startActivity(Intent(this, DebugVectorButtonStylesLightActivity::class.java)) startActivity(Intent(this, DebugVectorButtonStylesLightActivity::class.java))
@ -130,6 +132,10 @@ class DebugMenuActivity : VectorBaseActivity<ActivityDebugMenuBinding>() {
startActivity(Intent(this, DebugPrivateSettingsActivity::class.java)) startActivity(Intent(this, DebugPrivateSettingsActivity::class.java))
} }
private fun openMemoryLeaksSettings() {
startActivity(Intent(this, DebugMemoryLeaksActivity::class.java))
}
private fun renderQrCode(text: String) { private fun renderQrCode(text: String) {
views.debugQrCode.setData(text) views.debugQrCode.setData(text)
} }

View file

@ -0,0 +1,57 @@
/*
* Copyright (c) 2022 New Vector Ltd
*
* 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 im.vector.app.features.debug.di
import android.content.Context
import android.content.Intent
import dagger.Binds
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import im.vector.app.core.debug.DebugNavigator
import im.vector.app.core.debug.DebugReceiver
import im.vector.app.core.debug.FlipperProxy
import im.vector.app.core.debug.LeakDetector
import im.vector.app.features.debug.DebugMenuActivity
import im.vector.app.flipper.VectorFlipperProxy
import im.vector.app.leakcanary.LeakCanaryLeakDetector
import im.vector.app.receivers.VectorDebugReceiver
@InstallIn(SingletonComponent::class)
@Module
abstract class DebugModule {
companion object {
@Provides
fun providesDebugNavigator() = object : DebugNavigator {
override fun openDebugMenu(context: Context) {
context.startActivity(Intent(context, DebugMenuActivity::class.java))
}
}
}
@Binds
abstract fun bindsDebugReceiver(receiver: VectorDebugReceiver): DebugReceiver
@Binds
abstract fun bindsFlipperProxy(flipperProxy: VectorFlipperProxy): FlipperProxy
@Binds
abstract fun bindsLeakDetector(leakDetector: LeakCanaryLeakDetector): LeakDetector
}

View file

@ -24,6 +24,7 @@ import im.vector.app.core.di.MavericksAssistedViewModelFactory
import im.vector.app.core.di.MavericksViewModelComponent import im.vector.app.core.di.MavericksViewModelComponent
import im.vector.app.core.di.MavericksViewModelKey import im.vector.app.core.di.MavericksViewModelKey
import im.vector.app.features.debug.analytics.DebugAnalyticsViewModel import im.vector.app.features.debug.analytics.DebugAnalyticsViewModel
import im.vector.app.features.debug.leak.DebugMemoryLeaksViewModel
import im.vector.app.features.debug.settings.DebugPrivateSettingsViewModel import im.vector.app.features.debug.settings.DebugPrivateSettingsViewModel
@InstallIn(MavericksViewModelComponent::class) @InstallIn(MavericksViewModelComponent::class)
@ -39,4 +40,9 @@ interface MavericksViewModelDebugModule {
@IntoMap @IntoMap
@MavericksViewModelKey(DebugPrivateSettingsViewModel::class) @MavericksViewModelKey(DebugPrivateSettingsViewModel::class)
fun debugPrivateSettingsViewModelFactory(factory: DebugPrivateSettingsViewModel.Factory): MavericksAssistedViewModelFactory<*, *> fun debugPrivateSettingsViewModelFactory(factory: DebugPrivateSettingsViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
@Binds
@IntoMap
@MavericksViewModelKey(DebugMemoryLeaksViewModel::class)
fun debugMemoryLeaksViewModelFactory(factory: DebugMemoryLeaksViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
} }

View file

@ -90,6 +90,11 @@ class DebugFeaturesStateFactory @Inject constructor(
key = DebugFeatureKeys.newAppLayoutEnabled, key = DebugFeatureKeys.newAppLayoutEnabled,
factory = VectorFeatures::isNewAppLayoutEnabled factory = VectorFeatures::isNewAppLayoutEnabled
), ),
createBooleanFeature(
label = "Enable New Device Management",
key = DebugFeatureKeys.newDeviceManagementEnabled,
factory = VectorFeatures::isNewDeviceManagementEnabled
),
) )
) )
} }

View file

@ -79,6 +79,9 @@ class DebugVectorFeatures(
override fun isNewAppLayoutEnabled(): Boolean = read(DebugFeatureKeys.newAppLayoutEnabled) override fun isNewAppLayoutEnabled(): Boolean = read(DebugFeatureKeys.newAppLayoutEnabled)
?: vectorFeatures.isNewAppLayoutEnabled() ?: vectorFeatures.isNewAppLayoutEnabled()
override fun isNewDeviceManagementEnabled(): Boolean = read(DebugFeatureKeys.newDeviceManagementEnabled)
?: vectorFeatures.isNewDeviceManagementEnabled()
fun <T> override(value: T?, key: Preferences.Key<T>) = updatePreferences { fun <T> override(value: T?, key: Preferences.Key<T>) = updatePreferences {
if (value == null) { if (value == null) {
it.remove(key) it.remove(key)
@ -139,4 +142,5 @@ object DebugFeatureKeys {
val forceUsageOfOpusEncoder = booleanPreferencesKey("force-usage-of-opus-encoder") val forceUsageOfOpusEncoder = booleanPreferencesKey("force-usage-of-opus-encoder")
val startDmOnFirstMsg = booleanPreferencesKey("start-dm-on-first-msg") val startDmOnFirstMsg = booleanPreferencesKey("start-dm-on-first-msg")
val newAppLayoutEnabled = booleanPreferencesKey("new-app-layout-enabled") val newAppLayoutEnabled = booleanPreferencesKey("new-app-layout-enabled")
val newDeviceManagementEnabled = booleanPreferencesKey("new-device-management-enabled")
} }

View file

@ -0,0 +1,37 @@
/*
* Copyright (c) 2022 New Vector Ltd
*
* 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 im.vector.app.features.debug.leak
import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.core.extensions.addFragment
import im.vector.app.core.platform.VectorBaseActivity
import im.vector.app.databinding.ActivitySimpleBinding
@AndroidEntryPoint
class DebugMemoryLeaksActivity : VectorBaseActivity<ActivitySimpleBinding>() {
override fun getBinding() = ActivitySimpleBinding.inflate(layoutInflater)
override fun initUiAndData() {
if (isFirstCreation()) {
addFragment(
views.simpleFragmentContainer,
DebugMemoryLeaksFragment::class.java
)
}
}
}

View file

@ -0,0 +1,54 @@
/*
* Copyright (c) 2022 New Vector Ltd
*
* 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 im.vector.app.features.debug.leak
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.core.epoxy.onClick
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.databinding.FragmentDebugMemoryLeaksBinding
@AndroidEntryPoint
class DebugMemoryLeaksFragment : VectorBaseFragment<FragmentDebugMemoryLeaksBinding>() {
private val viewModel: DebugMemoryLeaksViewModel by fragmentViewModel()
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentDebugMemoryLeaksBinding {
return FragmentDebugMemoryLeaksBinding.inflate(inflater, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setViewListeners()
}
private fun setViewListeners() {
views.enableMemoryLeakAnalysis.onClick {
viewModel.handle(DebugMemoryLeaksViewActions.EnableMemoryLeaksAnalysis(views.enableMemoryLeakAnalysis.isChecked))
}
}
override fun invalidate() = withState(viewModel) { viewState ->
views.enableMemoryLeakAnalysis.isChecked = viewState.isMemoryLeaksAnalysisEnabled
}
}

View file

@ -0,0 +1,23 @@
/*
* Copyright (c) 2022 New Vector Ltd
*
* 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 im.vector.app.features.debug.leak
import im.vector.app.core.platform.VectorViewModelAction
sealed interface DebugMemoryLeaksViewActions : VectorViewModelAction {
data class EnableMemoryLeaksAnalysis(val isEnabled: Boolean) : DebugMemoryLeaksViewActions
}

View file

@ -0,0 +1,67 @@
/*
* Copyright (c) 2021 New Vector Ltd
*
* 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 im.vector.app.features.debug.leak
import com.airbnb.mvrx.MavericksViewModelFactory
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import im.vector.app.core.debug.LeakDetector
import im.vector.app.core.di.MavericksAssistedViewModelFactory
import im.vector.app.core.di.hiltMavericksViewModelFactory
import im.vector.app.core.platform.EmptyViewEvents
import im.vector.app.core.platform.VectorViewModel
import im.vector.app.features.settings.VectorPreferences
import kotlinx.coroutines.launch
class DebugMemoryLeaksViewModel @AssistedInject constructor(
@Assisted initialState: DebugMemoryLeaksViewState,
private val vectorPreferences: VectorPreferences,
private val leakDetector: LeakDetector,
) : VectorViewModel<DebugMemoryLeaksViewState, DebugMemoryLeaksViewActions, EmptyViewEvents>(initialState) {
@AssistedFactory
interface Factory : MavericksAssistedViewModelFactory<DebugMemoryLeaksViewModel, DebugMemoryLeaksViewState> {
override fun create(initialState: DebugMemoryLeaksViewState): DebugMemoryLeaksViewModel
}
companion object : MavericksViewModelFactory<DebugMemoryLeaksViewModel, DebugMemoryLeaksViewState> by hiltMavericksViewModelFactory()
init {
viewModelScope.launch {
refreshStateFromPreferences()
}
}
override fun handle(action: DebugMemoryLeaksViewActions) {
when (action) {
is DebugMemoryLeaksViewActions.EnableMemoryLeaksAnalysis -> handleEnableMemoryLeaksAnalysis(action)
}
}
private fun handleEnableMemoryLeaksAnalysis(action: DebugMemoryLeaksViewActions.EnableMemoryLeaksAnalysis) {
viewModelScope.launch {
vectorPreferences.enableMemoryLeakAnalysis(action.isEnabled)
leakDetector.enable(action.isEnabled)
refreshStateFromPreferences()
}
}
private fun refreshStateFromPreferences() {
setState { copy(isMemoryLeaksAnalysisEnabled = vectorPreferences.isMemoryLeakAnalysisEnabled()) }
}
}

View file

@ -0,0 +1,23 @@
/*
* Copyright (c) 2022 New Vector Ltd
*
* 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 im.vector.app.features.debug.leak
import com.airbnb.mvrx.MavericksState
data class DebugMemoryLeaksViewState(
val isMemoryLeaksAnalysisEnabled: Boolean = false
) : MavericksState

View file

@ -30,19 +30,19 @@ import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPl
import com.facebook.soloader.SoLoader import com.facebook.soloader.SoLoader
import com.kgurgul.flipper.RealmDatabaseDriver import com.kgurgul.flipper.RealmDatabaseDriver
import com.kgurgul.flipper.RealmDatabaseProvider import com.kgurgul.flipper.RealmDatabaseProvider
import im.vector.app.core.debug.FlipperProxy
import io.realm.RealmConfiguration import io.realm.RealmConfiguration
import okhttp3.Interceptor
import org.matrix.android.sdk.api.Matrix import org.matrix.android.sdk.api.Matrix
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@Singleton @Singleton
class FlipperProxy @Inject constructor( class VectorFlipperProxy @Inject constructor(
private val context: Context, private val context: Context,
) { ) : FlipperProxy {
private val networkFlipperPlugin = NetworkFlipperPlugin() private val networkFlipperPlugin = NetworkFlipperPlugin()
fun init(matrix: Matrix) { override fun init(matrix: Matrix) {
// https://github.com/facebook/flipper/issues/3572 // https://github.com/facebook/flipper/issues/3572
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) return if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) return
SoLoader.init(context, false) SoLoader.init(context, false)
@ -68,8 +68,5 @@ class FlipperProxy @Inject constructor(
} }
} }
@Suppress("RedundantNullableReturnType") override fun networkInterceptor() = FlipperOkhttpInterceptor(networkFlipperPlugin)
fun getNetworkInterceptor(): Interceptor? {
return FlipperOkhttpInterceptor(networkFlipperPlugin)
}
} }

View file

@ -0,0 +1,27 @@
/*
* Copyright (c) 2022 New Vector Ltd
*
* 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 im.vector.app.leakcanary
import im.vector.app.core.debug.LeakDetector
import leakcanary.LeakCanary
import javax.inject.Inject
class LeakCanaryLeakDetector @Inject constructor() : LeakDetector {
override fun enable(enable: Boolean) {
LeakCanary.config = LeakCanary.config.copy(dumpHeap = enable)
}
}

View file

@ -22,14 +22,24 @@ import android.content.Intent
import android.content.IntentFilter import android.content.IntentFilter
import android.content.SharedPreferences import android.content.SharedPreferences
import androidx.core.content.edit import androidx.core.content.edit
import im.vector.app.core.debug.DebugReceiver
import im.vector.app.core.di.DefaultSharedPreferences import im.vector.app.core.di.DefaultSharedPreferences
import im.vector.app.core.utils.lsFiles import im.vector.app.core.utils.lsFiles
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject
/** /**
* Receiver to handle some command from ADB * Receiver to handle some command from ADB
*/ */
class DebugReceiver : BroadcastReceiver() { class VectorDebugReceiver @Inject constructor() : BroadcastReceiver(), DebugReceiver {
override fun register(context: Context) {
context.registerReceiver(this, getIntentFilter(context))
}
override fun unregister(context: Context) {
context.unregisterReceiver(this)
}
override fun onReceive(context: Context, intent: Intent) { override fun onReceive(context: Context, intent: Intent) {
Timber.v("Received debug action: ${intent.action}") Timber.v("Received debug action: ${intent.action}")

View file

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/coordinatorLayout" android:id="@+id/coordinatorLayout"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -8,8 +9,11 @@
tools:ignore="HardcodedText"> tools:ignore="HardcodedText">
<ScrollView <ScrollView
android:id="@+id/scrollView2"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content"
app:layout_anchor="@+id/scrollView2"
app:layout_anchorGravity="center">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
@ -38,6 +42,12 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="Analytics" /> android:text="Analytics" />
<Button
android:id="@+id/debug_memory_leaks"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Memory leaks" />
<Button <Button
android:id="@+id/debug_test_text_view_link" android:id="@+id/debug_test_text_view_link"
android:layout_width="wrap_content" android:layout_width="wrap_content"

View file

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/coordinatorLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".features.debug.settings.DebugPrivateSettingsActivity"
tools:ignore="HardcodedText">
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:divider="@drawable/linear_divider"
android:orientation="vertical"
android:padding="@dimen/layout_horizontal_margin"
android:showDividers="middle">
<CheckBox
android:id="@+id/enableMemoryLeakAnalysis"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Enable memory leak analysis" />
</LinearLayout>
</ScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

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