diff --git a/.github/ISSUE_TEMPLATE/release.md b/.github/ISSUE_TEMPLATE/release.md new file mode 100644 index 0000000000..154e93286c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/release.md @@ -0,0 +1,84 @@ +--- +name: Release +about: Checklist for each release. To be used by the core team only. +title: "[Release] Element Android v" +labels: "\U0001F680 Release" +assignees: bmarty + +--- + +For the example, we are releasing the version 1.1.10. Delete this line and replace 1.1.10 with the version in the issue content. + +### Before the release + +- [ ] Weblate sync, fix lint issue if any (in a dedicated PR) +- [ ] Check the update of the store descriptions (using Google Translate if necessary) to ensure that the changes are acceptable to be published to the stores. +- [ ] Run the script `./tools/release/pushPlayStoreMetaData.sh`. You can check in the GooglePlay console the Activity log to check the effect. + +### Do the release + +- [ ] Create release with gitflow, branch name `release/1.1.10` +- [ ] Run `./tools/import_emojis.py` and commit the change if any. +- [ ] Run `./tools/import_sas_strings.py` and commit the change if any. If there is no change since a while, ping Travis +- [ ] Check the crashes from the PlayStore +- [ ] Check the rageshake with the current dev version: https://github.com/matrix-org/element-android-rageshakes/labels/1.1.10-dev +- [ ] Run the integration test, and especially `UiAllScreensSanityTest.allScreensTest()` +- [ ] Create an account on matrix.org +- [ ] Run towncrier: `towncrier --version v1.1.10 --draft` (remove `--draft` do write the file CHANGES.md) +- [ ] Add file for fastlane under ./fastlane/metadata/android/en-US/changelogs +- [ ] Push the branch and start a draft PR (will not be merged), to check that the CI is happy with all the changes. +- [ ] Finish release with gitflow, delete the draft PR +- [ ] Push `main` and the new tag `v1.1.10` to origin +- [ ] Checkout `develop` +- [ ] Increase version in `./vector/build.gradle` +- [ ] Commit and push `develop` +- [ ] Wait for [Buildkite](https://buildkite.com/matrix-dot-org/element-android/builds?branch=main) to build the `main` branch. +- [ ] Run the script `~/scripts/releaseElement.sh`. It will download the APKs from Buildkite check them and sign them. +- [ ] Install the APK on your phone to check that the upgrade went well (no init sync, etc.) +- [ ] Create a new beta release on the GooglePlay console and upload the 4 signed Apks. +- [ ] Check that the version codes are correct +- [ ] Copy the fastlane change to the GooglePlay console in the section en-GB. +- [ ] Push to beta release to 100% of the users +- [ ] Create the release on gitHub [from the tag](https://github.com/vector-im/element-android/tags), copy paste the block from the file CHANGES.md +- [ ] Add the 4 signed APKs to the GitHub release +- [ ] Ping the Android Internal room +- [ ] Add an entry in the internal diary + +### Once Live on PlayStore + +- [ ] Ping the Android public room and update its topic + +### After at least 2 days + +- [ ] Check the [rageshakes](https://github.com/matrix-org/element-android-rageshakes/issues) +- [ ] Check the crash reports on the GooglePlay console +- [ ] Check the Android Element room for any reported issues on the new version +- [ ] If all is OK, push to production and notify Markus (Bubu) to release the F-Droid version +- [ ] Ping the Android public room and update its topic with the new available version + +### Android SDK2 + +- [ ] Checkout the `main` branch on Element Android project + +#### On the SDK2 project + +https://github.com/matrix-org/matrix-android-sdk2 + +- [ ] Create a release with GitFlow +- [ ] Update the files `./build.gradle` and `./gradle/gradle-wrapper.properties` manually, to use the latest version for the dependency. You can get inspired by the same files on Element Android project. +- [ ] Run the script `./tools/import_from_element.sh` +- [ ] Update the version in `./matrix-sdk-android/build.gradle` and let the script finish to build the library +- [ ] Update the file `CHANGES.md` +- [ ] Finish the release using GitFlow +- [ ] Create the release on GitHub from [the tag](https://github.com/matrix-org/matrix-android-sdk2/tags) +- [ ] Upload the AAR on the GitHub release + +### Android SDK2 sample + +https://github.com/matrix-org/matrix-android-sdk2-sample + +- [ ] Update the dependency to the new version of the SDK2. Jitpack will have to build the AAR, it can take a few minutes. You can check status on https://jitpack.io/#matrix-org/matrix-android-sdk2 +- [ ] Build and run the sample, you may have to fix some API break +- [ ] Commit and push directly on `main` + + diff --git a/.idea/dictionaries/bmarty.xml b/.idea/dictionaries/bmarty.xml index 8299f1c4de..e143720aa9 100644 --- a/.idea/dictionaries/bmarty.xml +++ b/.idea/dictionaries/bmarty.xml @@ -38,6 +38,7 @@ unpublish unwedging vctr + wellknown \ No newline at end of file diff --git a/CHANGES.md b/CHANGES.md index 9947146a9e..a5ef37fb55 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,69 @@ +Changes in Element 1.1.14 (2021-07-23) +====================================== + +Features ✨ +---------- + - Add low priority section in DM tab ([#3463](https://github.com/vector-im/element-android/issues/3463)) + - Show missed call notification. ([#3710](https://github.com/vector-im/element-android/issues/3710)) + +Bugfixes 🐛 +---------- + - Don't use the transaction ID of the verification for the request ([#3589](https://github.com/vector-im/element-android/issues/3589)) + - Avoid incomplete downloads in cache ([#3656](https://github.com/vector-im/element-android/issues/3656)) + - Fix a crash which can happen when user signs out ([#3720](https://github.com/vector-im/element-android/issues/3720)) + - Ensure OTKs are uploaded when the session is created ([#3724](https://github.com/vector-im/element-android/issues/3724)) + +SDK API changes ⚠️ +------------------ + - Add initialState support to CreateRoomParams (#3713) ([#3713](https://github.com/vector-im/element-android/issues/3713)) + +Other changes +------------- + - Apply grammatical fixes to the Server ACL timeline messages. ([#3721](https://github.com/vector-im/element-android/issues/3721)) + - Add tags in the log, especially for VoIP, but can be used for other features in the future ([#3723](https://github.com/vector-im/element-android/issues/3723)) + + +Changes in Element v1.1.13 (2021-07-19) +======================================= + +Features ✨ +---------- + - Remove redundant mimetype (vector-im/element-web#2547) ([#3273](https://github.com/vector-im/element-android/issues/3273)) + - Room version capabilities and room upgrade support, better error feedback ([#3551](https://github.com/vector-im/element-android/issues/3551)) + - Add retry support in room addresses screen ([#3635](https://github.com/vector-im/element-android/issues/3635)) + - Better management of permission requests ([#3667](https://github.com/vector-im/element-android/issues/3667)) + +Bugfixes 🐛 +---------- + - Standardise spelling and casing of homeserver, identity server, and integration manager. ([#491](https://github.com/vector-im/element-android/issues/491)) + - Perform .well-known request first, even if the entered URL is a valid homeserver base url ([#2843](https://github.com/vector-im/element-android/issues/2843)) + - Use different copy for self verification. ([#3624](https://github.com/vector-im/element-android/issues/3624)) + - Crash when opening room addresses screen with no internet connection ([#3634](https://github.com/vector-im/element-android/issues/3634)) + - Fix unread messages marker being hidden in collapsed membership item ([#3655](https://github.com/vector-im/element-android/issues/3655)) + - Ensure reaction emoji picker tabs look fine on small displays ([#3661](https://github.com/vector-im/element-android/issues/3661)) + +SDK API changes ⚠️ +------------------ + - RawService.getWellknown() now takes a domain instead of a matrixId as parameter ([#3572](https://github.com/vector-im/element-android/issues/3572)) + + +Changes in Element 1.1.12 (2021-07-05) +====================================== + +Features ✨ +---------- + - Reveal password: use facility from com.google.android.material.textfield.TextInputLayout instead of manual handling. ([#3545](https://github.com/vector-im/element-android/issues/3545)) + - Implements new design for Jump to unread and quick fix visibility issues. ([#3547](https://github.com/vector-im/element-android/issues/3547)) + +Bugfixes 🐛 +---------- + - Fix some issues with timeline cache invalidation and visibility. ([#3542](https://github.com/vector-im/element-android/issues/3542)) + - Fix call invite processed after call is ended because of fastlane mode. ([#3564](https://github.com/vector-im/element-android/issues/3564)) + - Fix crash after video call. ([#3577](https://github.com/vector-im/element-android/issues/3577)) + - Fix crash out of memory ([#3583](https://github.com/vector-im/element-android/issues/3583)) + - CryptoStore migration has to be object to avoid crash ([#3605](https://github.com/vector-im/element-android/issues/3605)) + + Changes in Element v1.1.11 (2021-06-22) ======================================= diff --git a/Gemfile.lock b/Gemfile.lock index 6045f55496..345b4c1502 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -2,25 +2,25 @@ GEM remote: https://rubygems.org/ specs: CFPropertyList (3.0.3) - addressable (2.7.0) + addressable (2.8.0) public_suffix (>= 2.0.2, < 5.0) artifactory (3.0.15) atomos (0.1.3) aws-eventstream (1.1.1) - aws-partitions (1.462.0) - aws-sdk-core (3.114.0) + aws-partitions (1.479.0) + aws-sdk-core (3.117.0) aws-eventstream (~> 1, >= 1.0.2) aws-partitions (~> 1, >= 1.239.0) aws-sigv4 (~> 1.1) jmespath (~> 1.0) - aws-sdk-kms (1.43.0) + aws-sdk-kms (1.44.0) aws-sdk-core (~> 3, >= 3.112.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.95.1) + aws-sdk-s3 (1.96.1) aws-sdk-core (~> 3, >= 3.112.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.1) - aws-sigv4 (1.2.3) + aws-sigv4 (1.2.4) aws-eventstream (~> 1, >= 1.0.2) babosa (1.0.4) claide (1.0.3) @@ -35,13 +35,15 @@ GEM unf (>= 0.0.5, < 1.0.0) dotenv (2.7.6) emoji_regex (3.2.2) - excon (0.81.0) - faraday (1.4.2) + excon (0.85.0) + faraday (1.5.1) faraday-em_http (~> 1.0) faraday-em_synchrony (~> 1.0) faraday-excon (~> 1.1) + faraday-httpclient (~> 1.0.1) faraday-net_http (~> 1.0) faraday-net_http_persistent (~> 1.1) + faraday-patron (~> 1.0) multipart-post (>= 1.2, < 3) ruby2_keywords (>= 0.0.4) faraday-cookie_jar (0.0.7) @@ -50,12 +52,14 @@ GEM faraday-em_http (1.0.0) faraday-em_synchrony (1.0.0) faraday-excon (1.1.0) + faraday-httpclient (1.0.1) faraday-net_http (1.0.1) - faraday-net_http_persistent (1.1.0) + faraday-net_http_persistent (1.2.0) + faraday-patron (1.0.0) faraday_middleware (1.0.0) faraday (~> 1.0) - fastimage (2.2.3) - fastlane (2.184.0) + fastimage (2.2.4) + fastlane (2.187.0) CFPropertyList (>= 2.3, < 4.0.0) addressable (>= 2.3, < 3.0.0) artifactory (~> 3.0) @@ -94,37 +98,36 @@ GEM xcpretty (~> 0.3.0) xcpretty-travis-formatter (>= 0.0.3) gh_inspector (1.1.3) - google-apis-androidpublisher_v3 (0.4.0) - google-apis-core (~> 0.1) - google-apis-core (0.3.0) + google-apis-androidpublisher_v3 (0.8.0) + google-apis-core (>= 0.4, < 2.a) + google-apis-core (0.4.0) addressable (~> 2.5, >= 2.5.1) - googleauth (~> 0.14) - httpclient (>= 2.8.1, < 3.0) + googleauth (>= 0.16.2, < 2.a) + httpclient (>= 2.8.1, < 3.a) mini_mime (~> 1.0) representable (~> 3.0) - retriable (>= 2.0, < 4.0) + retriable (>= 2.0, < 4.a) rexml - signet (~> 0.14) webrick - google-apis-iamcredentials_v1 (0.4.0) - google-apis-core (~> 0.1) - google-apis-playcustomapp_v1 (0.3.0) - google-apis-core (~> 0.1) - google-apis-storage_v1 (0.4.0) - google-apis-core (~> 0.1) + google-apis-iamcredentials_v1 (0.6.0) + google-apis-core (>= 0.4, < 2.a) + google-apis-playcustomapp_v1 (0.5.0) + google-apis-core (>= 0.4, < 2.a) + google-apis-storage_v1 (0.6.0) + google-apis-core (>= 0.4, < 2.a) google-cloud-core (1.6.0) google-cloud-env (~> 1.0) google-cloud-errors (~> 1.0) google-cloud-env (1.5.0) faraday (>= 0.17.3, < 2.0) google-cloud-errors (1.1.0) - google-cloud-storage (1.31.1) + google-cloud-storage (1.34.1) addressable (~> 2.5) digest-crc (~> 0.4) google-apis-iamcredentials_v1 (~> 0.1) google-apis-storage_v1 (~> 0.1) - google-cloud-core (~> 1.2) - googleauth (~> 0.9) + google-cloud-core (~> 1.6) + googleauth (>= 0.16.2, < 2.a) mini_mime (~> 1.0) googleauth (0.16.2) faraday (>= 0.17.3, < 2.0) @@ -134,7 +137,7 @@ GEM os (>= 0.9, < 2.0) signet (~> 0.14) highline (2.0.3) - http-cookie (1.0.3) + http-cookie (1.0.4) domain_name (~> 0.5) httpclient (2.8.3) jmespath (1.4.0) @@ -150,7 +153,7 @@ GEM os (1.1.1) plist (3.6.0) public_suffix (4.0.6) - rake (13.0.3) + rake (13.0.6) representable (3.1.1) declarative (< 0.1.0) trailblazer-option (>= 0.1.1, < 0.2.0) @@ -158,8 +161,8 @@ GEM retriable (3.1.2) rexml (3.2.5) rouge (2.0.7) - ruby2_keywords (0.0.4) - rubyzip (2.3.0) + ruby2_keywords (0.0.5) + rubyzip (2.3.2) security (0.1.3) signet (0.15.0) addressable (~> 2.3) @@ -184,12 +187,13 @@ GEM unicode-display_width (1.7.0) webrick (1.7.0) word_wrap (1.0.0) - xcodeproj (1.19.0) + xcodeproj (1.20.0) CFPropertyList (>= 2.3.3, < 4.0) atomos (~> 0.1.3) claide (>= 1.0.2, < 2.0) colored2 (~> 3.1) nanaimo (~> 0.3.0) + rexml (~> 3.2.4) xcpretty (0.3.0) rouge (~> 2.0.7) xcpretty-travis-formatter (1.0.1) diff --git a/attachment-viewer/build.gradle b/attachment-viewer/build.gradle index 4b95b20029..c393c5f483 100644 --- a/attachment-viewer/build.gradle +++ b/attachment-viewer/build.gradle @@ -55,9 +55,9 @@ dependencies { implementation 'io.reactivex.rxjava2:rxandroid:2.1.1' implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" - implementation 'androidx.core:core-ktx:1.5.0' - implementation 'androidx.appcompat:appcompat:1.3.0' + implementation 'androidx.core:core-ktx:1.6.0' + implementation 'androidx.appcompat:appcompat:1.3.1' implementation "androidx.recyclerview:recyclerview:1.2.1" - implementation 'com.google.android.material:material:1.3.0' + implementation 'com.google.android.material:material:1.4.0' } \ No newline at end of file diff --git a/build.gradle b/build.gradle index b6c4a17559..bbb6b343cf 100644 --- a/build.gradle +++ b/build.gradle @@ -2,7 +2,7 @@ buildscript { // Ref: https://kotlinlang.org/releases.html - ext.kotlin_version = '1.5.20' + ext.kotlin_version = '1.5.21' ext.kotlin_coroutines_version = "1.5.0" repositories { google() @@ -12,7 +12,7 @@ buildscript { } } dependencies { - classpath 'com.android.tools.build:gradle:4.2.1' + classpath 'com.android.tools.build:gradle:4.2.2' classpath 'com.google.gms:google-services:4.3.8' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.3' diff --git a/changelog.d/3545.feature b/changelog.d/3545.feature deleted file mode 100644 index f582affbf2..0000000000 --- a/changelog.d/3545.feature +++ /dev/null @@ -1 +0,0 @@ -Reveal password: use facility from com.google.android.material.textfield.TextInputLayout instead of manual handling. \ No newline at end of file diff --git a/changelog.d/3547.feature b/changelog.d/3547.feature deleted file mode 100644 index 8921932067..0000000000 --- a/changelog.d/3547.feature +++ /dev/null @@ -1 +0,0 @@ -Implements new design for Jump to unread and quick fix visibility issues. \ No newline at end of file diff --git a/changelog.d/3564.bugfix b/changelog.d/3564.bugfix deleted file mode 100644 index 74f71ccded..0000000000 --- a/changelog.d/3564.bugfix +++ /dev/null @@ -1 +0,0 @@ -Fix call invite processed after call is ended because of fastlane mode. \ No newline at end of file diff --git a/changelog.d/3577.bugfix b/changelog.d/3577.bugfix deleted file mode 100644 index 6b3917292f..0000000000 --- a/changelog.d/3577.bugfix +++ /dev/null @@ -1 +0,0 @@ -Fix crash after video call. \ No newline at end of file diff --git a/docs/identity_server.md b/docs/identity_server.md index 0d75108dd3..e765ae3949 100644 --- a/docs/identity_server.md +++ b/docs/identity_server.md @@ -4,7 +4,7 @@ Issue: #607 PR: #1354 ## Introduction -Identity Servers support contact discovery on Matrix by letting people look up Third Party Identifiers to see if the owner has publicly linked them with their Matrix ID. +Identity servers support contact discovery on Matrix by letting people look up Third Party Identifiers to see if the owner has publicly linked them with their Matrix ID. ## Implementation @@ -87,6 +87,6 @@ This screen displays the identity server configuration and the binding of the us This screen is a form to set a new identity server URL ## Ref: -- https://matrix.org/blog/2019/09/27/privacy-improvements-in-synapse-1-4-and-riot-1-4 is a good summary of the role of an Identity server and the proper way to configure and use it in respect to the privacy and the consent of the user. +- https://matrix.org/blog/2019/09/27/privacy-improvements-in-synapse-1-4-and-riot-1-4 is a good summary of the role of an identity server and the proper way to configure and use it in respect to the privacy and the consent of the user. - API documentation: https://matrix.org/docs/spec/identity_service/latest - vector.im TOS: https://vector.im/identity-server-privacy-notice diff --git a/docs/notifications.md b/docs/notifications.md index a00fef8fae..b44984785a 100644 --- a/docs/notifications.md +++ b/docs/notifications.md @@ -2,11 +2,11 @@ This document aims to describe how Element android displays notifications to the # Table of Contents 1. [Prerequisites Knowledge](#prerequisites-knowledge) - * [How does a matrix client get a message from a Home Server?](#how-does-a-matrix-client-get-a-message-from-a-home-server) + * [How does a matrix client get a message from a homeserver?](#how-does-a-matrix-client-get-a-message-from-a-homeserver) * [How does a mobile app receives push notification?](#how-does-a-mobile-app-receives-push-notification) * [Push VS Notification](#push-vs-notification) * [Push in the matrix federated world](#push-in-the-matrix-federated-world) - * [How does the Home Server knows when to notify a client?](#how-does-the-home-server-knows-when-to-notify-a-client) + * [How does the homeserver know when to notify a client?](#how-does-the-homeserver-know-when-to-notify-a-client) * [Push vs privacy, and mitigation](#push-vs-privacy-and-mitigation) * [Background processing limitations](#background-processing-limitations) 2. [Element Notification implementations](#element-notification-implementations) @@ -22,9 +22,9 @@ First let's start with some prerequisite knowledge # Prerequisites Knowledge -## How does a matrix client get a message from a Home Server? +## How does a matrix client get a message from a homeserver? -In order to get messages from a home server, a matrix client need to perform a ``sync`` operation. +In order to get messages from a homeserver, a matrix client need to perform a ``sync`` operation. `To read events, the intended flow of operation is for clients to first call the /sync API without a since parameter. This returns the most recent message events for each room, as well as the state of the room at the start of the returned timeline. ` @@ -90,7 +90,7 @@ That means that Element Android, a matrix client created by New Vector, is using If you create your own matrix client, you will also need to deploy an instance of a **Push Gateway** with the credentials needed to use FCM for your app. -On registration, a matrix client must tell to it's Home Server what Push Gateway to use. +On registration, a matrix client must tell its homeserver what Push Gateway to use. See [Sygnal](https://github.com/matrix-org/sygnal/) for a reference implementation. ``` @@ -122,13 +122,13 @@ Recommended reading: * https://matrix.org/docs/spec/client_server/r0.4.0.html#id128 -## How does the Home Server knows when to notify a client? +## How does the homeserver know when to notify a client? This is defined by [**push rules**](https://matrix.org/docs/spec/client_server/r0.4.0.html#push-rules-). `A push rule is a single rule that states under what conditions an event should be passed onto a push gateway and how the notification should be presented (sound / importance).` -A Home Server can be configured with default rules (for Direct messages, group messages, mentions, etc.. ). +A homeserver can be configured with default rules (for Direct messages, group messages, mentions, etc.. ). There are different kind of push rules, it can be per room (each new message on this room should be notified), it can also define a pattern that a message should match (when you are mentioned, or key word based). @@ -187,7 +187,7 @@ In background, and depending on wether push is available or not, Element will us ## Push (FCM) received in background -In order to enable Push, Element must first get a push token from the firebase SDK, then register a pusher with this token on the HomeServer. +In order to enable Push, Element must first get a push token from the firebase SDK, then register a pusher with this token on the homeserver. When a message should be notified to a user, the user's homeserver notifies the registered `push gateway` for Element, that is [sygnal](https://github.com/matrix-org/sygnal) _- The reference implementation for push gateways -_ hosted by matrix.org. @@ -199,7 +199,7 @@ Homeserver ----> Sygnal (configured for Element) ----> FCM ----> Element The push gateway is configured to only send `(eventId,roomId)` in the push payload (for better [privacy](#push-vs-privacy-and-mitigation)). -Element needs then to synchronise with the user's HomeServer, in order to resolve the event and create a notification. +Element needs then to synchronise with the user's homeserver, in order to resolve the event and create a notification. As per [Google recommendation](https://android-developers.googleblog.com/2018/09/notifying-your-users-with-fcm.html), Element will then use the WorkManager API in order to trigger a background sync. @@ -217,7 +217,7 @@ Homeserver ----> Sygnal ----> FCM ----> Element **Possible outcomes** -Upon reception of the FCM push, Element will perform a sync call to the Home Server, during this process it is possible that: +Upon reception of the FCM push, Element will perform a sync call to the homeserver, during this process it is possible that: * Happy path, the sync is performed, the message resolved and displayed in the notification drawer * The notified message is not in the sync. Can happen if a lot of things did happen since the push (`gappy sync`) * The sync generates additional notifications (e.g an encrypted message where the user is mentioned detected locally) diff --git a/fastlane/metadata/android/cs-CZ/changelogs/40101070.txt b/fastlane/metadata/android/cs-CZ/changelogs/40101070.txt new file mode 100644 index 0000000000..2a6afb21a5 --- /dev/null +++ b/fastlane/metadata/android/cs-CZ/changelogs/40101070.txt @@ -0,0 +1,2 @@ +Hlavní změny v této verzi: beta podpora pro Spaces. Komprimace videa před odesláním. +Úplný záznam změn: https://github.com/vector-im/element-android/releases/tag/v1.1.7 diff --git a/fastlane/metadata/android/cs-CZ/changelogs/40101080.txt b/fastlane/metadata/android/cs-CZ/changelogs/40101080.txt new file mode 100644 index 0000000000..5ec173ebea --- /dev/null +++ b/fastlane/metadata/android/cs-CZ/changelogs/40101080.txt @@ -0,0 +1,2 @@ +Hlavní změny v této verzi: vylepšení pro Spaces +Úplný záznam změn: https://github.com/vector-im/element-android/releases/tag/v1.1.8 diff --git a/fastlane/metadata/android/cs-CZ/changelogs/40101090.txt b/fastlane/metadata/android/cs-CZ/changelogs/40101090.txt new file mode 100644 index 0000000000..782a2fa8c5 --- /dev/null +++ b/fastlane/metadata/android/cs-CZ/changelogs/40101090.txt @@ -0,0 +1,2 @@ +Hlavní změny v této verzi: doplněna podpora pro síť gitter.im +Úplný záznam změn: https://github.com/vector-im/element-android/releases/tag/v1.1.9 diff --git a/fastlane/metadata/android/cs-CZ/changelogs/40101100.txt b/fastlane/metadata/android/cs-CZ/changelogs/40101100.txt new file mode 100644 index 0000000000..de73b6f382 --- /dev/null +++ b/fastlane/metadata/android/cs-CZ/changelogs/40101100.txt @@ -0,0 +1,2 @@ +Hlavní změny v této verzi: aktualizace vzhledu a stylu a nové funkce prostorů. +Úplný záznam změn: https://github.com/vector-im/element-android/releases/tag/v1.1.10 diff --git a/fastlane/metadata/android/cs-CZ/changelogs/40101110.txt b/fastlane/metadata/android/cs-CZ/changelogs/40101110.txt new file mode 100644 index 0000000000..c4bfee0779 --- /dev/null +++ b/fastlane/metadata/android/cs-CZ/changelogs/40101110.txt @@ -0,0 +1,2 @@ +Hlavní změny v této verzi: aktualizace vzhledu a stylu a nové funkce prostorů (bugfix pro 1.1.10) +Úplný záznam změn: https://github.com/vector-im/element-android/releases/tag/v1.1.11 diff --git a/fastlane/metadata/android/de-DE/changelogs/40101100.txt b/fastlane/metadata/android/de-DE/changelogs/40101100.txt new file mode 100644 index 0000000000..04f944cdcf --- /dev/null +++ b/fastlane/metadata/android/de-DE/changelogs/40101100.txt @@ -0,0 +1,2 @@ +Hauptänderungen: Design-Update und neue Features für Spaces +Vollständige Änderungsliste: https://github.com/vector-im/element-android/releases/tag/v1.1.10 diff --git a/fastlane/metadata/android/de-DE/changelogs/40101110.txt b/fastlane/metadata/android/de-DE/changelogs/40101110.txt new file mode 100644 index 0000000000..8e115469e1 --- /dev/null +++ b/fastlane/metadata/android/de-DE/changelogs/40101110.txt @@ -0,0 +1,2 @@ +Hauptänderungen: Design-Update und neue Features für Spaces (Bugfix für 1.1.10) +Vollständige Änderungsliste: https://github.com/vector-im/element-android/releases/tag/v1.1.11 diff --git a/fastlane/metadata/android/en-US/changelogs/40101120.txt b/fastlane/metadata/android/en-US/changelogs/40101120.txt new file mode 100644 index 0000000000..6118974777 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/40101120.txt @@ -0,0 +1,2 @@ +Main changes in this version: theme and style update and fix a crash after video call +Full changelog: https://github.com/vector-im/element-android/releases/tag/v1.1.12 \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/40101130.txt b/fastlane/metadata/android/en-US/changelogs/40101130.txt new file mode 100644 index 0000000000..9fc3f23b3e --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/40101130.txt @@ -0,0 +1,2 @@ +Main changes in this version: mainly stability and bugfixes update. +Full changelog: https://github.com/vector-im/element-android/releases/tag/v1.1.13 \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/40101140.txt b/fastlane/metadata/android/en-US/changelogs/40101140.txt new file mode 100644 index 0000000000..ee04069968 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/40101140.txt @@ -0,0 +1,2 @@ +Main changes in this version: fix an issue about encrypted messages. +Full changelog: https://github.com/vector-im/element-android/releases/tag/v1.1.14 \ No newline at end of file diff --git a/fastlane/metadata/android/et/changelogs/40101100.txt b/fastlane/metadata/android/et/changelogs/40101100.txt new file mode 100644 index 0000000000..e00e6de393 --- /dev/null +++ b/fastlane/metadata/android/et/changelogs/40101100.txt @@ -0,0 +1,2 @@ +Põhilised muutused selles versioonis: teemade ja välimuse uuendused ning mõned kogukondade uuendused +Kogu ingliskeelne muudatuste logi: https://github.com/vector-im/element-android/releases/tag/v1.1.10 diff --git a/fastlane/metadata/android/et/changelogs/40101110.txt b/fastlane/metadata/android/et/changelogs/40101110.txt new file mode 100644 index 0000000000..a4629c92d0 --- /dev/null +++ b/fastlane/metadata/android/et/changelogs/40101110.txt @@ -0,0 +1,2 @@ +Põhilised muutused selles versioonis: teemade ja välimuse uuendused ning mõned kogukondade uuendused (1.1.10 veaparandus) +Kogu ingliskeelne muudatuste logi: https://github.com/vector-im/element-android/releases/tag/v1.1.11 diff --git a/fastlane/metadata/android/fr-FR/changelogs/40101070.txt b/fastlane/metadata/android/fr-FR/changelogs/40101070.txt new file mode 100644 index 0000000000..66cc5d1671 --- /dev/null +++ b/fastlane/metadata/android/fr-FR/changelogs/40101070.txt @@ -0,0 +1,2 @@ +Principaux changements pour cette version : prise en charge des espaces en bêta. Compression des vidéos avant envoi. +Intégralité des changements : https://github.com/vector-im/element-android/releases/tag/v1.1.7 diff --git a/fastlane/metadata/android/fr-FR/changelogs/40101080.txt b/fastlane/metadata/android/fr-FR/changelogs/40101080.txt new file mode 100644 index 0000000000..31a4b72363 --- /dev/null +++ b/fastlane/metadata/android/fr-FR/changelogs/40101080.txt @@ -0,0 +1,2 @@ +Principaux changements pour cette version : amélioration des espaces. +Intégralité des changements : https://github.com/vector-im/element-android/releases/tag/v1.1.8 diff --git a/fastlane/metadata/android/fr-FR/changelogs/40101090.txt b/fastlane/metadata/android/fr-FR/changelogs/40101090.txt new file mode 100644 index 0000000000..99f02f1bb2 --- /dev/null +++ b/fastlane/metadata/android/fr-FR/changelogs/40101090.txt @@ -0,0 +1,2 @@ +Principaux changements pour cette version : ajout de la prise en charge de gitter.im +Intégralité des changements : https://github.com/vector-im/element-android/releases/tag/v1.1.9 diff --git a/fastlane/metadata/android/fr-FR/full_description.txt b/fastlane/metadata/android/fr-FR/full_description.txt index 066b94868b..78fcdf5617 100644 --- a/fastlane/metadata/android/fr-FR/full_description.txt +++ b/fastlane/metadata/android/fr-FR/full_description.txt @@ -1,30 +1,39 @@ -Element est une nouvelle application de messagerie et de collaboration qui : +Element est à la fois une messagerie sécurisée et une application de collaboration en équipe, idéale pour les conversations de groupe en télétravail. Cette application utilise le chiffrement de bout en bout. Elle permet de mettre en place des téléconférences vidéo, du partage de fichier et des appels vocaux. -1. Vous permet de préserver votre vie privée -2. Vous permet de communiquer avec n’importe qui sur réseau Matrix, et plus encore grâce aux intégrations d’autres applications telles que Slack ou Discord -3. Vous protège de la publicité et de la collecte de données -4. Vous protège grâce au chiffrement de bout-à-bout et à la signature croisée pour authentifier les autres utilisateurs +Les fonctionnalités d’Element incluent : +- Outils de communication en ligne avancés +- Communication d’entreprise sécurisée par le chiffrement de bout en bout des messages, même pour les travailleurs à distance +- Messagerie décentralisée basée sur le framework open source Matrix +- Partage sécurisé de fichiers avec chiffrement des données lors de la gestion de projet +- Conversations vidéo par voix sur IP et partage d’écran +- Intégration facile avec vos outils de collaboration, de gestion de projet, services de VoIP et autres applications de messagerie -Element est complètement différente des autres applications de messagerie et de collaboration puisque l’application est décentralisée et open-source. +Element est complètement différente des autres applications de messagerie et de collaboration. Elle s’appuie sur Matrix, un réseau ouvert de communication décentralisée. Elle permet l’auto-hébergement pour que ses utilisateurs restent le plus en contrôle possible de leurs données et leurs messages. -Element vous permet d’héberger vous-même ou de choisir un hôte vous permettant d’assurer votre vie privée, la propriété et le contrôle de vos données et de vos conversations. Cela vous donne accès à un réseau ouvert. Vous n’êtes donc pas condamné à parler à d’autres utilisateurs d’Element seulement. Et c'est très sécurisé. +Confidentialité et messagerie chiffrée +Element vous protège des publicités non désirées, du minage de données et des prisons dorées. Elle protègé vos données et vos communications vocales grâce au chiffrement de bout en bout et à la vérification de signature croisée entre appareils. -Element peut faire tout ça car elle est basée sur Matrix, le protocole standard pour la communication ouverte et décentralisée. +Element vous donne la main sur votre confidentialité en vous permettant de communiquer de manière sécurisée avec tout le réseau Matrix ou d’autres applications de communication d’entreprise au travers d’intégrations d’applications comme Slack. -Element vous donne le contrôle en vous laissant choisir qui héberge vos conversations. Depuis l'application Element, vous pouvez choisir votre hôte de différentes manières : +Element peut être auto-hébergé +Pour une meilleure souveraineté sur vos données et conversations, Element peut être auto-hébergé ou vous pouvez choisir votre hôte Matrix - la norme open source pour les communications décentralisées. Element garantit votre confidentialité, conformité aux normes de sécurité, tout en proposant une intégration souple. -1. Créer un compte gratuit sur le serveur public matrix.org hébergé par les développeurs de Matrix, ou choisir parmi les milliers de serveurs public hébergés par des bénévoles -2. Héberger vous-même votre compte en installant un serveur sur votre propre machine -3. Créer un compte sur un serveur personnalisé en souscrivant sur la plateforme d'hébergement « Element Matrix Services » (EMS) +Vos données vous appartiennent +Vous décidez où stocker vos données et messages. Aucun risque de minage de données où d’accès par des tierce parties. -Pourquoi choisir Element ? +Element vous place aux commandes de différente manières : +1. Inscrivez vous sur le serveur public matrix.org hébergé par les développeurs de Matrix ou choisissez parmi des milliers de serveurs publics hébergés par des bénévoles +2. Auto-hébergez votre compte sur un serveur de votre proper infrastructure informatique +3. Inscrivez vous à la plateforme d’hébergement Element Matrix Services -VOS DONNÉES VOUS APPARTIENNENT : vous décidez où stocker vos données et messages. Ils vous appartiennent et vous les maîtrisez. Aucune multinationale ne viendra extraire vos données pour les envoyer au plus offrant. +Messagerie et collaboration ouvertes +Vous pouvez discuter avec tout le réseau Matrix, que vos interlocuteurs utilisent Element, une autre application Matrix, ou même s’ils utilisent une application complètement différente. -MESSAGERIE ET COLLABORATION OUVERTES : vous pouvez discuter avec tout le réseau Matrix, qu’ils utilisent Element ou une autre application Matrix, même s’ils utilisent une autre plateforme de messagerie telle que Slack, IRC ou XMPP. +Ultra sécurisé +Chiffrement de bout en bout (seules les personnes dans la conversation peuvent déchiffrer les messages) et vérification de signature croisée entre appareils. -ULTRA SÉCURISÉ : chiffrement de bout en bout (seuls les membres d’une conversation peuvent déchiffrer les messages), et signature croisée pour vérifier les appareils de vos interlocuteurs. +Communication et intégration parfaites +Messagerie instantannée, appels audio et vidéo, partage de fichier, partage d’écran et bien d’autres intégrations, bots et widgets. Lancez des salons, des communautés, restez en contact et menez vos projets à bien. -TOUTES VOS COMMUNICATIONS : messagerie, appels audio et vidéo, partage de fichier, partage d’écran et un grand nombre d’intégrations, robots et widgets. Participez à des salons, des communautés, restez en contact et faites avancer vos projets. - -PARTOUT AVEC VOUS : votre historique reste synchronisé entre tous vos appareils et sur le web sur https://element.io/app. +Reprenez où vous vous êtes arrêté +Restez en contact où que vous soyez grâce à l’historique des messages synchronisé entre tous vos appareils et sur le web sur https://app.element.io diff --git a/fastlane/metadata/android/hu-HU/changelogs/40101100.txt b/fastlane/metadata/android/hu-HU/changelogs/40101100.txt new file mode 100644 index 0000000000..34171b2221 --- /dev/null +++ b/fastlane/metadata/android/hu-HU/changelogs/40101100.txt @@ -0,0 +1,2 @@ +Főbb változtatások ebben a verzióban: kinézet és stílus frissítések és új funkciók a terekhez +Teljes változásnapló: https://github.com/vector-im/element-android/releases/tag/v1.1.10 diff --git a/fastlane/metadata/android/hu-HU/changelogs/40101110.txt b/fastlane/metadata/android/hu-HU/changelogs/40101110.txt new file mode 100644 index 0000000000..1550736f36 --- /dev/null +++ b/fastlane/metadata/android/hu-HU/changelogs/40101110.txt @@ -0,0 +1,2 @@ +Főbb változtatások ebben a verzióban: kinézet és stílus frissítések és új funkciók a terekhez (hibajavítás az 1.1.10-hez) +Teljes változásnapló: https://github.com/vector-im/element-android/releases/tag/v1.1.11 diff --git a/fastlane/metadata/android/it-IT/changelogs/40101100.txt b/fastlane/metadata/android/it-IT/changelogs/40101100.txt new file mode 100644 index 0000000000..6f2447e5f6 --- /dev/null +++ b/fastlane/metadata/android/it-IT/changelogs/40101100.txt @@ -0,0 +1,2 @@ +Modifiche principali in questa versione: aggiornati tema e stile e nuove funzioni per gli spazi . +Cronologia completa: https://github.com/vector-im/element-android/releases/tag/v1.1.10 diff --git a/fastlane/metadata/android/it-IT/changelogs/40101110.txt b/fastlane/metadata/android/it-IT/changelogs/40101110.txt new file mode 100644 index 0000000000..263f46b4f1 --- /dev/null +++ b/fastlane/metadata/android/it-IT/changelogs/40101110.txt @@ -0,0 +1,2 @@ +Modifiche principali in questa versione: aggiornati tema e stile e nuove funzioni per gli spazi (bugfix per 1.1.10) +Cronologia completa: https://github.com/vector-im/element-android/releases/tag/v1.1.11 diff --git a/fastlane/metadata/android/pt-BR/changelogs/40101070.txt b/fastlane/metadata/android/pt-BR/changelogs/40101070.txt index ab403ea4cc..5667b1609a 100644 --- a/fastlane/metadata/android/pt-BR/changelogs/40101070.txt +++ b/fastlane/metadata/android/pt-BR/changelogs/40101070.txt @@ -1,2 +1,2 @@ -Principais mudanças nesta version: suporte beta para Espaços. Comprimir vídeo antes de enviar. +Principais mudanças nesta versão: suporte beta para Espaços. Comprimir vídeo antes de enviar. Changelog completo: https://github.com/vector-im/element-android/releases/tag/v1.1.7 diff --git a/fastlane/metadata/android/pt-BR/changelogs/40101080.txt b/fastlane/metadata/android/pt-BR/changelogs/40101080.txt index 25047345ef..7922e6d800 100644 --- a/fastlane/metadata/android/pt-BR/changelogs/40101080.txt +++ b/fastlane/metadata/android/pt-BR/changelogs/40101080.txt @@ -1,2 +1,2 @@ -Principais mudanças nesta version: melhoramento para Espaços. +Principais mudanças nesta versão: melhoramento para Espaços. Changelog completo: https://github.com/vector-im/element-android/releases/tag/v1.1.8 diff --git a/fastlane/metadata/android/pt-BR/changelogs/40101090.txt b/fastlane/metadata/android/pt-BR/changelogs/40101090.txt index cc5e71cf7f..3246596eab 100644 --- a/fastlane/metadata/android/pt-BR/changelogs/40101090.txt +++ b/fastlane/metadata/android/pt-BR/changelogs/40101090.txt @@ -1,2 +1,2 @@ -Principais mudanças nesta version: adicionar supporte a rede gitter.im. +Principais mudanças nesta versão: adicionar supporte a rede gitter.im. Changelog completo: https://github.com/vector-im/element-android/releases/tag/v1.1.9 diff --git a/fastlane/metadata/android/pt-BR/changelogs/40101100.txt b/fastlane/metadata/android/pt-BR/changelogs/40101100.txt new file mode 100644 index 0000000000..4efd042313 --- /dev/null +++ b/fastlane/metadata/android/pt-BR/changelogs/40101100.txt @@ -0,0 +1,2 @@ +Principais mudanças nesta versão: atualização de tema e estilo e novas funcionalidades para espaços. +Changelog completo: https://github.com/vector-im/element-android/releases/tag/v1.1.10 diff --git a/fastlane/metadata/android/pt-BR/changelogs/40101110.txt b/fastlane/metadata/android/pt-BR/changelogs/40101110.txt new file mode 100644 index 0000000000..ac98ef9e3b --- /dev/null +++ b/fastlane/metadata/android/pt-BR/changelogs/40101110.txt @@ -0,0 +1,2 @@ +Principais mudanças nesta versão: atualização de tema e estilo e novas funcionalidades para espaços (bugfix para 1.1.10) +Changelog completo: https://github.com/vector-im/element-android/releases/tag/v1.1.11 diff --git a/fastlane/metadata/android/uk/changelogs/40101100.txt b/fastlane/metadata/android/uk/changelogs/40101100.txt new file mode 100644 index 0000000000..c1fde35579 --- /dev/null +++ b/fastlane/metadata/android/uk/changelogs/40101100.txt @@ -0,0 +1,2 @@ +Основні зміни цієї версії: оновлено зовнішній вигляд та нові можливості для просторів +Вичерпний перелік змін: https://github.com/vector-im/element-android/releases/tag/v1.1.10 diff --git a/fastlane/metadata/android/uk/changelogs/40101110.txt b/fastlane/metadata/android/uk/changelogs/40101110.txt new file mode 100644 index 0000000000..9aa1195e49 --- /dev/null +++ b/fastlane/metadata/android/uk/changelogs/40101110.txt @@ -0,0 +1,2 @@ +Основні зміни цієї версії: оновлено зовнішній вигляд та нові можливості для просторів (bugfix для 1.1.10) +Вичерпний перелік змін: https://github.com/vector-im/element-android/releases/tag/v1.1.11 diff --git a/fastlane/metadata/android/zh-CN/changelogs/40101100.txt b/fastlane/metadata/android/zh-CN/changelogs/40101100.txt new file mode 100644 index 0000000000..b748f34290 --- /dev/null +++ b/fastlane/metadata/android/zh-CN/changelogs/40101100.txt @@ -0,0 +1,2 @@ +此版本的主要变化:主题和样式更新以及空间的新功能。 +完整更新日志:https://github.com/vector-im/element-android/releases/tag/v1.1.10 diff --git a/fastlane/metadata/android/zh-CN/changelogs/40101110.txt b/fastlane/metadata/android/zh-CN/changelogs/40101110.txt new file mode 100644 index 0000000000..ef3f46e07d --- /dev/null +++ b/fastlane/metadata/android/zh-CN/changelogs/40101110.txt @@ -0,0 +1,2 @@ +此版本的主要变化:主题和样式更新以及空间的新功能(1.1.10 的错误修复) +完整更新日志:https://github.com/vector-im/element-android/releases/tag/v1.1.11 diff --git a/fastlane/metadata/android/zh-TW/changelogs/40101100.txt b/fastlane/metadata/android/zh-TW/changelogs/40101100.txt new file mode 100644 index 0000000000..08e081fd8b --- /dev/null +++ b/fastlane/metadata/android/zh-TW/changelogs/40101100.txt @@ -0,0 +1,2 @@ +此版本中的主要變動:佈景主題與樣式更新,以及空間的新功能。 +完整的變更紀錄:https://github.com/vector-im/element-android/releases/tag/v1.1.10 diff --git a/fastlane/metadata/android/zh-TW/changelogs/40101110.txt b/fastlane/metadata/android/zh-TW/changelogs/40101110.txt new file mode 100644 index 0000000000..91bbc18fff --- /dev/null +++ b/fastlane/metadata/android/zh-TW/changelogs/40101110.txt @@ -0,0 +1,2 @@ +此版本中的主要變動:佈景主題與樣式更新,以及空間的新功能(1.1.10 的臭蟲修復版本) +完整的變更紀錄:https://github.com/vector-im/element-android/releases/tag/v1.1.11 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 283500479a..17ba19021b 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=a9e356a21595348b6f04b024ed0b08ac8aea6b2ac37e6c0ef58e51549cd7b9cb -distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-all.zip +distributionSha256Sum=9bb8bc05f562f2d42bdf1ba8db62f6b6fa1c3bf6c392228802cc7cb0578fe7e0 +distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/library/ui-styles/build.gradle b/library/ui-styles/build.gradle index 47c4664636..4d34195962 100644 --- a/library/ui-styles/build.gradle +++ b/library/ui-styles/build.gradle @@ -52,8 +52,8 @@ android { } dependencies { - implementation 'androidx.appcompat:appcompat:1.3.0' - implementation 'com.google.android.material:material:1.3.0' + implementation 'androidx.appcompat:appcompat:1.3.1' + implementation 'com.google.android.material:material:1.4.0' // Pref theme implementation 'androidx.preference:preference-ktx:1.1.1' // PFLockScreen attrs diff --git a/matrix-sdk-android-rx/build.gradle b/matrix-sdk-android-rx/build.gradle index 0d4aa7fc84..899432b498 100644 --- a/matrix-sdk-android-rx/build.gradle +++ b/matrix-sdk-android-rx/build.gradle @@ -35,7 +35,7 @@ android { dependencies { implementation project(":matrix-sdk-android") - implementation 'androidx.appcompat:appcompat:1.3.0' + implementation 'androidx.appcompat:appcompat:1.3.1' implementation 'io.reactivex.rxjava2:rxkotlin:2.4.0' implementation 'io.reactivex.rxjava2:rxandroid:2.1.1' implementation "org.jetbrains.kotlinx:kotlinx-coroutines-rx2:$kotlin_coroutines_version" diff --git a/matrix-sdk-android/build.gradle b/matrix-sdk-android/build.gradle index e8d1c1b018..fbaae97fdc 100644 --- a/matrix-sdk-android/build.gradle +++ b/matrix-sdk-android/build.gradle @@ -9,7 +9,7 @@ buildscript { mavenCentral() } dependencies { - classpath "io.realm:realm-gradle-plugin:10.6.0" + classpath "io.realm:realm-gradle-plugin:10.6.1" } } @@ -126,7 +126,7 @@ dependencies { def lifecycle_version = '2.2.0' def arch_version = '2.1.0' def markwon_version = '3.1.0' - def daggerVersion = '2.37' + def daggerVersion = '2.38' def work_version = '2.5.0' def retrofit_version = '2.9.0' @@ -136,8 +136,8 @@ dependencies { implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version" - implementation "androidx.appcompat:appcompat:1.3.0" - implementation "androidx.core:core-ktx:1.5.0" + implementation "androidx.appcompat:appcompat:1.3.1" + implementation "androidx.core:core-ktx:1.6.0" implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version" implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version" @@ -185,30 +185,30 @@ dependencies { implementation 'com.otaliastudios:transcoder:0.10.3' // Phone number https://github.com/google/libphonenumber - implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.26' + implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.28' testImplementation 'junit:junit:4.13.2' testImplementation 'org.robolectric:robolectric:4.5.1' //testImplementation 'org.robolectric:shadows-support-v4:3.0' // Note: version sticks to 1.9.2 due to https://github.com/mockk/mockk/issues/281 - testImplementation 'io.mockk:mockk:1.11.0' - testImplementation 'org.amshove.kluent:kluent-android:1.67' + testImplementation 'io.mockk:mockk:1.12.0' + testImplementation 'org.amshove.kluent:kluent-android:1.68' testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version" // Plant Timber tree for test testImplementation 'net.lachlanmckee:timber-junit-rule:1.0.1' kaptAndroidTest "com.google.dagger:dagger-compiler:$daggerVersion" - androidTestImplementation 'androidx.test:core:1.3.0' - androidTestImplementation 'androidx.test:runner:1.3.0' - androidTestImplementation 'androidx.test:rules:1.3.0' - androidTestImplementation 'androidx.test.ext:junit:1.1.2' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' - androidTestImplementation 'org.amshove.kluent:kluent-android:1.65' - androidTestImplementation 'io.mockk:mockk-android:1.11.0' + androidTestImplementation 'androidx.test:core:1.4.0' + androidTestImplementation 'androidx.test:runner:1.4.0' + androidTestImplementation 'androidx.test:rules:1.4.0' + androidTestImplementation 'androidx.test.ext:junit:1.1.3' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' + androidTestImplementation 'org.amshove.kluent:kluent-android:1.68' + androidTestImplementation 'io.mockk:mockk-android:1.12.0' androidTestImplementation "androidx.arch.core:core-testing:$arch_version" androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version" // Plant Timber tree for test androidTestImplementation 'net.lachlanmckee:timber-junit-rule:1.0.1' - androidTestUtil 'androidx.test:orchestrator:1.3.0' + androidTestUtil 'androidx.test:orchestrator:1.4.0' } diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CommonTestHelper.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CommonTestHelper.kt index 287a4233d9..6e07223ac7 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CommonTestHelper.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CommonTestHelper.kt @@ -78,7 +78,7 @@ class CommonTestHelper(context: Context) { } /** - * Create a Home server configuration, with Http connection allowed for test + * Create a homeserver configuration, with Http connection allowed for test */ fun createHomeServerConfig(): HomeServerConnectionConfig { return HomeServerConnectionConfig.Builder() diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupTest.kt index eb8b8b9730..89d297c592 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupTest.kt @@ -816,7 +816,7 @@ class KeysBackupTest : InstrumentedTest { // - Do an e2e backup to the homeserver mKeysBackupTestHelper.prepareAndCreateKeysBackupData(keysBackup) - // Get key backup version from the home server + // Get key backup version from the homeserver val keysVersionResult = mTestHelper.doSync { keysBackup.getCurrentVersion(it) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixPatterns.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixPatterns.kt index 7f5f3f54ef..9a5e40ffeb 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixPatterns.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixPatterns.kt @@ -16,8 +16,12 @@ package org.matrix.android.sdk.api +import org.matrix.android.sdk.BuildConfig +import timber.log.Timber + /** * This class contains pattern to match the different Matrix ids + * Ref: https://matrix.org/docs/spec/appendices#identifier-grammar */ object MatrixPatterns { @@ -25,7 +29,7 @@ object MatrixPatterns { private const val DOMAIN_REGEX = ":[A-Z0-9.-]+(:[0-9]{2,5})?" // regex pattern to find matrix user ids in a string. - // See https://matrix.org/speculator/spec/HEAD/appendices.html#historical-user-ids + // See https://matrix.org/docs/spec/appendices#historical-user-ids private const val MATRIX_USER_IDENTIFIER_REGEX = "@[A-Z0-9\\x21-\\x39\\x3B-\\x7F]+$DOMAIN_REGEX" val PATTERN_CONTAIN_MATRIX_USER_IDENTIFIER = MATRIX_USER_IDENTIFIER_REGEX.toRegex(RegexOption.IGNORE_CASE) @@ -154,7 +158,7 @@ object MatrixPatterns { * Orders which are not strings, or do not consist solely of ascii characters in the range \x20 (space) to \x7E (~), * or consist of more than 50 characters, are forbidden and the field should be ignored if received. */ - fun isValidOrderString(order: String?) : Boolean { + fun isValidOrderString(order: String?): Boolean { return order != null && order.length < 50 && order matches ORDER_STRING_REGEX } @@ -163,4 +167,18 @@ object MatrixPatterns { "[^a-z0-9._%#@=+-]".toRegex().replace(it, "") } } + + /** + * Return the domain form a userId + * Examples: + * - "@alice:domain.org".getDomain() will return "domain.org" + * - "@bob:domain.org:3455".getDomain() will return "domain.org:3455" + */ + fun String.getDomain(): String { + if (BuildConfig.DEBUG && !isUserId(this)) { + // They are some invalid userId localpart in the wild, but the domain part should be there anyway + Timber.w("Not a valid user ID: $this") + } + return substringAfter(":") + } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/HomeServerConnectionConfig.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/HomeServerConnectionConfig.kt index e1c5171bfc..215f0a0351 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/HomeServerConnectionConfig.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/HomeServerConnectionConfig.kt @@ -18,11 +18,11 @@ package org.matrix.android.sdk.api.auth.data import android.net.Uri import com.squareup.moshi.JsonClass +import okhttp3.CipherSuite +import okhttp3.TlsVersion import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig.Builder import org.matrix.android.sdk.internal.network.ssl.Fingerprint import org.matrix.android.sdk.internal.util.ensureTrailingSlash -import okhttp3.CipherSuite -import okhttp3.TlsVersion /** * This data class holds how to connect to a specific Homeserver. @@ -31,7 +31,12 @@ import okhttp3.TlsVersion */ @JsonClass(generateAdapter = true) data class HomeServerConnectionConfig( + // This is the homeserver URL entered by the user val homeServerUri: Uri, + // This is the homeserver base URL for the client-server API. Default to homeServerUri, + // but can be updated with data from .Well-Known before login, and/or with the data + // included in the login response + val homeServerUriBase: Uri = homeServerUri, val identityServerUri: Uri? = null, val antiVirusServerUri: Uri? = null, val allowedFingerprints: List = emptyList(), @@ -47,7 +52,6 @@ data class HomeServerConnectionConfig( * This builder should be use to create a [HomeServerConnectionConfig] instance. */ class Builder { - private lateinit var homeServerUri: Uri private var identityServerUri: Uri? = null private var antiVirusServerUri: Uri? = null @@ -69,14 +73,14 @@ data class HomeServerConnectionConfig( */ fun withHomeServerUri(hsUri: Uri): Builder { if (hsUri.scheme != "http" && hsUri.scheme != "https") { - throw RuntimeException("Invalid home server URI: $hsUri") + throw RuntimeException("Invalid homeserver URI: $hsUri") } // ensure trailing / val hsString = hsUri.toString().ensureTrailingSlash() homeServerUri = try { Uri.parse(hsString) } catch (e: Exception) { - throw RuntimeException("Invalid home server URI: $hsUri") + throw RuntimeException("Invalid homeserver URI: $hsUri") } return this } @@ -134,7 +138,7 @@ data class HomeServerConnectionConfig( } /** - * Add an accepted TLS version for TLS connections with the home server. + * Add an accepted TLS version for TLS connections with the homeserver. * * @param tlsVersion the tls version to add to the set of TLS versions accepted. * @return this builder @@ -156,7 +160,7 @@ data class HomeServerConnectionConfig( } /** - * Add a TLS cipher suite to the list of accepted TLS connections with the home server. + * Add a TLS cipher suite to the list of accepted TLS connections with the homeserver. * * @param tlsCipherSuite the tls cipher suite to add. * @return this builder @@ -234,16 +238,16 @@ data class HomeServerConnectionConfig( */ fun build(): HomeServerConnectionConfig { return HomeServerConnectionConfig( - homeServerUri, - identityServerUri, - antiVirusServerUri, - allowedFingerprints, - shouldPin, - tlsVersions, - tlsCipherSuites, - shouldAcceptTlsExtensions, - allowHttpExtension, - forceUsageTlsVersions + homeServerUri = homeServerUri, + identityServerUri = identityServerUri, + antiVirusServerUri = antiVirusServerUri, + allowedFingerprints = allowedFingerprints, + shouldPin = shouldPin, + tlsVersions = tlsVersions, + tlsCipherSuites = tlsCipherSuites, + shouldAcceptTlsExtensions = shouldAcceptTlsExtensions, + allowHttpExtension = allowHttpExtension, + forceUsageTlsVersions = forceUsageTlsVersions ) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/SessionParams.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/SessionParams.kt index b2a57c7f5c..b490ac877e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/SessionParams.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/SessionParams.kt @@ -51,13 +51,18 @@ data class SessionParams( val deviceId = credentials.deviceId /** - * The current homeserver Url. It can be different that the homeserver url entered - * during login phase, because a redirection may have occurred + * The homeserver Url entered by the user during the login phase. */ val homeServerUrl = homeServerConnectionConfig.homeServerUri.toString() /** - * The current homeserver host + * The current homeserver Url for client-server API. It can be different that the homeserver url entered + * during login phase, because a redirection may have occurred + */ + val homeServerUrlBase = homeServerConnectionConfig.homeServerUriBase.toString() + + /** + * The current homeserver host, using what has been entered by the user during login phase */ val homeServerHost = homeServerConnectionConfig.homeServerUri.host diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/registration/RegistrationFlowResponse.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/registration/RegistrationFlowResponse.kt index 2b1c1c09b3..ac740ddab7 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/registration/RegistrationFlowResponse.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/registration/RegistrationFlowResponse.kt @@ -38,7 +38,7 @@ data class RegistrationFlowResponse( val completedStages: List? = null, /** - * The session identifier that the client must pass back to the home server, if one is provided, + * The session identifier that the client must pass back to the homeserver, if one is provided, * in subsequent attempts to authenticate in the same API call. */ @Json(name = "session") diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/wellknown/WellknownResult.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/wellknown/WellknownResult.kt index c68a9e9699..56257db79c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/wellknown/WellknownResult.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/wellknown/WellknownResult.kt @@ -22,11 +22,6 @@ import org.matrix.android.sdk.api.auth.data.WellKnown * Ref: https://matrix.org/docs/spec/client_server/latest#well-known-uri */ sealed class WellknownResult { - /** - * The provided matrixId is no valid. Unable to extract a domain name. - */ - object InvalidMatrixId : WellknownResult() - /** * Retrieve the specific piece of information from the user in a way which fits within the existing client user experience, * if the client is inclined to do so. Failure can take place instead if no good user experience for this is possible at this point. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/MatrixIdFailure.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/MatrixIdFailure.kt new file mode 100644 index 0000000000..8f7bca803d --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/MatrixIdFailure.kt @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2021 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.api.failure + +sealed class MatrixIdFailure : Failure.FeatureFailure() { + object InvalidMatrixId : MatrixIdFailure() +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/logger/LoggerTag.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/logger/LoggerTag.kt new file mode 100644 index 0000000000..51f9b50699 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/logger/LoggerTag.kt @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2021 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.api.logger + +/** + * Parent class for custom logger tags. Can be used with Timber : + * + * val loggerTag = LoggerTag("MyTag", LoggerTag.VOIP) + * Timber.tag(loggerTag.value).v("My log message") + */ +open class LoggerTag(_value: String, parentTag: LoggerTag? = null) { + + object VOIP : LoggerTag("VOIP") + + val value: String = if (parentTag == null) { + _value + } else { + "${parentTag.value}/$_value" + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/raw/RawService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/raw/RawService.kt index f1722b2189..3366d040f7 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/raw/RawService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/raw/RawService.kt @@ -29,8 +29,10 @@ interface RawService { /** * Specific case for the well-known file. Cache validity is 8 hours + * @param domain the domain to get the .well-known file, for instance "matrix.org". + * The URL will be "https://{domain}/.well-known/matrix/client" */ - suspend fun getWellknown(userId: String): String + suspend fun getWellknown(domain: String): String /** * Clear all the cache data diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/CallState.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/CallState.kt index 2dbd1c9b01..47a63b4a25 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/CallState.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/CallState.kt @@ -16,6 +16,8 @@ package org.matrix.android.sdk.api.session.call +import org.matrix.android.sdk.api.session.room.model.call.EndCallReason + sealed class CallState { /** Idle, setting up objects */ @@ -42,6 +44,6 @@ sealed class CallState { * */ data class Connected(val iceConnectionState: MxPeerConnectionState) : CallState() - /** Terminated. Incoming/Outgoing call, the call is terminated */ - object Terminated : CallState() + /** Ended. Incoming/Outgoing call, the call is terminated */ + data class Ended(val reason: EndCallReason? = null) : CallState() } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/MxCall.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/MxCall.kt index fcc9f7072d..dd23e81cc6 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/MxCall.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/MxCall.kt @@ -18,7 +18,7 @@ package org.matrix.android.sdk.api.session.call import org.matrix.android.sdk.api.session.room.model.call.CallCandidate import org.matrix.android.sdk.api.session.room.model.call.CallCapabilities -import org.matrix.android.sdk.api.session.room.model.call.CallHangupContent +import org.matrix.android.sdk.api.session.room.model.call.EndCallReason import org.matrix.android.sdk.api.session.room.model.call.SdpType import org.matrix.android.sdk.api.util.Optional @@ -69,7 +69,7 @@ interface MxCall : MxCallDetail { /** * End the call */ - fun hangUp(reason: CallHangupContent.Reason? = null) + fun hangUp(reason: EndCallReason? = null) /** * Start a call diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupService.kt index 465d00168f..4464427b90 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupService.kt @@ -28,7 +28,7 @@ import org.matrix.android.sdk.internal.crypto.store.SavedKeyBackupKeyInfo interface KeysBackupService { /** - * Retrieve the current version of the backup from the home server + * Retrieve the current version of the backup from the homeserver * * It can be different than keysBackupVersion. * @param callback onSuccess(null) will be called if there is no backup on the server diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupState.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupState.kt index 7d0f04ebcf..a4cc133398 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupState.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupState.kt @@ -54,7 +54,7 @@ enum class KeysBackupState { // Need to check the current backup version on the homeserver Unknown, - // Checking if backup is enabled on home server + // Checking if backup is enabled on homeserver CheckingBackUpOnHomeserver, // Backup has been stopped because a new backup version has been detected on the homeserver diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/Event.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/Event.kt index 6400dd6444..3d82846e7e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/Event.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/Event.kt @@ -104,7 +104,7 @@ data class Event( /** * The `age` value transcoded in a timestamp based on the device clock when the SDK received - * the event from the home server. + * the event from the homeserver. * Unlike `age`, this value is static. */ @Transient diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilities.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilities.kt index da99ab8d54..10c2db4535 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilities.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilities.kt @@ -32,7 +32,13 @@ data class HomeServerCapabilities( /** * Default identity server url, provided in Wellknown */ - val defaultIdentityServerUrl: String? = null + val defaultIdentityServerUrl: String? = null, + /** + * Room versions supported by the server + * This capability describes the default and available room versions a server supports, and at what level of stability. + * Clients should make use of this capability to determine if users need to be encouraged to upgrade their rooms. + */ + val roomVersions: RoomVersionCapabilities? = null ) { companion object { const val MAX_UPLOAD_FILE_SIZE_UNKNOWN = -1L diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/RoomVersionModel.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/RoomVersionModel.kt new file mode 100644 index 0000000000..7798b4cc63 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/RoomVersionModel.kt @@ -0,0 +1,32 @@ +/* + * Copyright 2021 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.api.session.homeserver + +data class RoomVersionCapabilities( + val defaultRoomVersion: String, + val supportedVersion: List +) + +data class RoomVersionInfo( + val version: String, + val status: RoomVersionStatus +) + +enum class RoomVersionStatus { + STABLE, + UNSTABLE +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/Room.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/Room.kt index cb04b05a74..ebe96b6382 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/Room.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/Room.kt @@ -34,6 +34,7 @@ import org.matrix.android.sdk.api.session.room.tags.TagsService import org.matrix.android.sdk.api.session.room.timeline.TimelineService import org.matrix.android.sdk.api.session.room.typing.TypingService import org.matrix.android.sdk.api.session.room.uploads.UploadsService +import org.matrix.android.sdk.api.session.room.version.RoomVersionService import org.matrix.android.sdk.api.session.search.SearchResult import org.matrix.android.sdk.api.session.space.Space import org.matrix.android.sdk.api.util.Optional @@ -57,7 +58,8 @@ interface Room : RelationService, RoomCryptoService, RoomPushRuleService, - RoomAccountDataService { + RoomAccountDataService, + RoomVersionService { /** * The roomId of this room diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomSummaryQueryParams.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomSummaryQueryParams.kt index 88ec2de768..b440857518 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomSummaryQueryParams.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomSummaryQueryParams.kt @@ -39,12 +39,6 @@ fun spaceSummaryQueryParams(init: (RoomSummaryQueryParams.Builder.() -> Unit) = .build() } -enum class RoomCategoryFilter { - ONLY_DM, - ONLY_ROOMS, - ALL -} - /** * This class can be used to filter room summaries to use with: * [org.matrix.android.sdk.api.session.room.Room] and [org.matrix.android.sdk.api.session.room.RoomService] @@ -59,11 +53,10 @@ data class RoomSummaryQueryParams( val excludeType: List?, val includeType: List?, val activeSpaceFilter: ActiveSpaceFilter?, - var activeGroupId: String? = null + val activeGroupId: String? = null ) { class Builder { - var roomId: QueryStringValue = QueryStringValue.IsNotEmpty var displayName: QueryStringValue = QueryStringValue.IsNotEmpty var canonicalAlias: QueryStringValue = QueryStringValue.NoCondition diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallHangupContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallHangupContent.kt index 9d6e1a7eae..31f801dd6f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallHangupContent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallHangupContent.kt @@ -43,29 +43,5 @@ data class CallHangupContent( * or `invite_timeout` for when the other party did not answer in time. * One of: ["ice_failed", "invite_timeout"] */ - @Json(name = "reason") val reason: Reason? = null -) : CallSignalingContent { - @JsonClass(generateAdapter = false) - enum class Reason { - @Json(name = "ice_failed") - ICE_FAILED, - - @Json(name = "ice_timeout") - ICE_TIMEOUT, - - @Json(name = "user_hangup") - USER_HANGUP, - - @Json(name = "replaced") - REPLACED, - - @Json(name = "user_media_failed") - USER_MEDIA_FAILED, - - @Json(name = "invite_timeout") - INVITE_TIMEOUT, - - @Json(name = "unknown_error") - UNKWOWN_ERROR - } -} + @Json(name = "reason") val reason: EndCallReason? = null +) : CallSignalingContent diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallRejectContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallRejectContent.kt index ea412fbe3e..1b9a7186e2 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallRejectContent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallRejectContent.kt @@ -36,5 +36,10 @@ data class CallRejectContent( /** * Required. The version of the VoIP specification this message adheres to. */ - @Json(name = "version") override val version: String? + @Json(name = "version") override val version: String?, + + /** + * Optional error reason for the reject. + */ + @Json(name = "reason") val reason: EndCallReason? = null ) : CallSignalingContent diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/EndCallReason.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/EndCallReason.kt new file mode 100644 index 0000000000..60e038b2f9 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/EndCallReason.kt @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2021 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.api.session.room.model.call + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = false) +enum class EndCallReason { + @Json(name = "ice_failed") + ICE_FAILED, + + @Json(name = "ice_timeout") + ICE_TIMEOUT, + + @Json(name = "user_hangup") + USER_HANGUP, + + @Json(name = "replaced") + REPLACED, + + @Json(name = "user_media_failed") + USER_MEDIA_FAILED, + + @Json(name = "invite_timeout") + INVITE_TIMEOUT, + + @Json(name = "unknown_error") + UNKWOWN_ERROR, + + @Json(name = "user_busy") + USER_BUSY, + + @Json(name = "answered_elsewhere") + ANSWERED_ELSEWHERE +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/CreateRoomParams.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/CreateRoomParams.kt index ca8c66bb3b..c46d7d0fd2 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/CreateRoomParams.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/CreateRoomParams.kt @@ -25,7 +25,6 @@ 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 -// TODO Give a way to include other initial states open class CreateRoomParams { /** * A public visibility indicates that the room will be shown in the published room list. @@ -103,6 +102,13 @@ open class CreateRoomParams { */ val creationContent = mutableMapOf() + /** + * A list of state events to set in the new room. This allows the user to override the default state events + * set in the new room. The expected format of the state events are an object with type, state_key and content keys set. + * Takes precedence over events set by preset, but gets overridden by name and topic keys. + */ + val initialStates = mutableListOf() + /** * Set to true to disable federation of this room. * Default: false diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/CreateRoomStateEvent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/CreateRoomStateEvent.kt new file mode 100644 index 0000000000..fcfdc3e333 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/CreateRoomStateEvent.kt @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2021 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.api.session.room.model.create + +import org.matrix.android.sdk.api.session.events.model.Content + +data class CreateRoomStateEvent( + /** + * Required. The type of event to send. + */ + val type: String, + + /** + * Required. The content of the event. + */ + val content: Content, + + /** + * The state_key of the state event. Defaults to an empty string. + */ + val stateKey: String = "" +) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageAudioContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageAudioContent.kt index fcf3d73cbe..b4ba5c0a66 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageAudioContent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageAudioContent.kt @@ -54,5 +54,5 @@ data class MessageAudioContent( ) : MessageWithAttachmentContent { override val mimeType: String? - get() = encryptedFileInfo?.mimetype ?: audioInfo?.mimeType + get() = audioInfo?.mimeType } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageFileContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageFileContent.kt index d93f115322..96877b4d9f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageFileContent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageFileContent.kt @@ -60,8 +60,7 @@ data class MessageFileContent( ) : MessageWithAttachmentContent { override val mimeType: String? - get() = encryptedFileInfo?.mimetype - ?: info?.mimeType + get() = info?.mimeType ?: MimeTypeMap.getFileExtensionFromUrl(filename ?: body)?.let { extension -> MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageImageContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageImageContent.kt index 73e27b64e3..73fd1eab56 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageImageContent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageImageContent.kt @@ -20,7 +20,6 @@ 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.MimeTypes import org.matrix.android.sdk.internal.crypto.model.rest.EncryptedFileInfo @JsonClass(generateAdapter = true) @@ -55,5 +54,5 @@ data class MessageImageContent( @Json(name = "file") override val encryptedFileInfo: EncryptedFileInfo? = null ) : MessageImageInfoContent { override val mimeType: String? - get() = encryptedFileInfo?.mimetype ?: info?.mimeType ?: MimeTypes.Images + get() = info?.mimeType } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageStickerContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageStickerContent.kt index 280316d4b5..8e1d4d3d75 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageStickerContent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageStickerContent.kt @@ -55,5 +55,5 @@ data class MessageStickerContent( @Json(name = "file") override val encryptedFileInfo: EncryptedFileInfo? = null ) : MessageImageInfoContent { override val mimeType: String? - get() = encryptedFileInfo?.mimetype ?: info?.mimeType + get() = info?.mimeType } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageVideoContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageVideoContent.kt index b7581c9fbf..3f5d2dab2e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageVideoContent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageVideoContent.kt @@ -53,5 +53,5 @@ data class MessageVideoContent( @Json(name = "file") override val encryptedFileInfo: EncryptedFileInfo? = null ) : MessageWithAttachmentContent { override val mimeType: String? - get() = encryptedFileInfo?.mimetype ?: videoInfo?.mimeType + get() = videoInfo?.mimeType } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/version/RoomVersionService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/version/RoomVersionService.kt new file mode 100644 index 0000000000..ea67b55174 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/version/RoomVersionService.kt @@ -0,0 +1,45 @@ +/* + * Copyright 2021 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.api.session.room.version + +interface RoomVersionService { + /** + * Return the room version of this room + */ + fun getRoomVersion(): String + + /** + * Upgrade to the given room version + * @return the replacement room id + */ + suspend fun upgradeToVersion(version: String): String + + /** + * Get the recommended room version for the current homeserver + */ + fun getRecommendedVersion() : String + + /** + * Ask if the user has enough power level to upgrade the room + */ + fun userMayUpgradeRoom(userId: String): Boolean + + /** + * Return true if the current room version is declared unstable by the homeserver + */ + fun isUsingUnstableRoomVersion(): Boolean +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/Space.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/Space.kt index db25762c2f..3bae6126e0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/Space.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/Space.kt @@ -18,6 +18,7 @@ package org.matrix.android.sdk.api.session.space import org.matrix.android.sdk.api.session.room.Room import org.matrix.android.sdk.api.session.room.model.RoomSummary +import org.matrix.android.sdk.api.session.space.model.SpaceChildContent interface Space { @@ -38,6 +39,8 @@ interface Space { autoJoin: Boolean = false, suggested: Boolean? = false) + fun getChildInfo(roomId: String): SpaceChildContent? + suspend fun removeChildren(roomId: String) @Throws diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/AuthAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/AuthAPI.kt index 5a9fa9edf6..50d9e5a06c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/AuthAPI.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/AuthAPI.kt @@ -21,8 +21,8 @@ import org.matrix.android.sdk.api.util.JsonDict import org.matrix.android.sdk.internal.auth.data.Availability import org.matrix.android.sdk.internal.auth.data.LoginFlowResponse import org.matrix.android.sdk.internal.auth.data.PasswordLoginParams -import org.matrix.android.sdk.internal.auth.data.RiotConfig import org.matrix.android.sdk.internal.auth.data.TokenLoginParams +import org.matrix.android.sdk.internal.auth.data.WebClientConfig import org.matrix.android.sdk.internal.auth.login.ResetPasswordMailConfirmed import org.matrix.android.sdk.internal.auth.registration.AddThreePidRegistrationParams import org.matrix.android.sdk.internal.auth.registration.AddThreePidRegistrationResponse @@ -44,16 +44,16 @@ import retrofit2.http.Url */ internal interface AuthAPI { /** - * Get a Riot config file, using the name including the domain + * Get a Web client config file, using the name including the domain */ @GET("config.{domain}.json") - suspend fun getRiotConfigDomain(@Path("domain") domain: String): RiotConfig + suspend fun getWebClientConfigDomain(@Path("domain") domain: String): WebClientConfig /** - * Get a Riot config file + * Get a Web client default config file */ @GET("config.json") - suspend fun getRiotConfig(): RiotConfig + suspend fun getWebClientConfig(): WebClientConfig /** * Get the version information of the homeserver diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt index 20ce438d8e..e76dc28734 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt @@ -19,6 +19,8 @@ package org.matrix.android.sdk.internal.auth import android.net.Uri import dagger.Lazy import okhttp3.OkHttpClient +import org.matrix.android.sdk.api.MatrixPatterns +import org.matrix.android.sdk.api.MatrixPatterns.getDomain import org.matrix.android.sdk.api.auth.AuthenticationService import org.matrix.android.sdk.api.auth.data.Credentials import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig @@ -28,10 +30,11 @@ import org.matrix.android.sdk.api.auth.login.LoginWizard import org.matrix.android.sdk.api.auth.registration.RegistrationWizard import org.matrix.android.sdk.api.auth.wellknown.WellknownResult import org.matrix.android.sdk.api.failure.Failure +import org.matrix.android.sdk.api.failure.MatrixIdFailure import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.util.appendParamToUrl import org.matrix.android.sdk.internal.SessionManager -import org.matrix.android.sdk.internal.auth.data.RiotConfig +import org.matrix.android.sdk.internal.auth.data.WebClientConfig import org.matrix.android.sdk.internal.auth.db.PendingSessionData import org.matrix.android.sdk.internal.auth.login.DefaultLoginWizard import org.matrix.android.sdk.internal.auth.login.DirectLoginTask @@ -122,7 +125,7 @@ internal class DefaultAuthenticationService @Inject constructor( private fun getHomeServerUrlBase(): String? { return pendingSessionData ?.homeServerConnectionConfig - ?.homeServerUri + ?.homeServerUriBase ?.toString() ?.trim { it == '/' } } @@ -143,9 +146,9 @@ internal class DefaultAuthenticationService @Inject constructor( return result.fold( { // The homeserver exists and up to date, keep the config - // Homeserver url may have been changed, if it was a Riot url + // Homeserver url may have been changed, if it was a Web client url val alteredHomeServerConnectionConfig = homeServerConnectionConfig.copy( - homeServerUri = Uri.parse(it.homeServerUrl) + homeServerUriBase = Uri.parse(it.homeServerUrl) ) pendingSessionData = PendingSessionData(alteredHomeServerConnectionConfig) @@ -154,7 +157,7 @@ internal class DefaultAuthenticationService @Inject constructor( }, { if (it is UnrecognizedCertificateException) { - throw Failure.UnrecognizedCertificateFailure(homeServerConnectionConfig.homeServerUri.toString(), it.fingerprint) + throw Failure.UnrecognizedCertificateFailure(homeServerConnectionConfig.homeServerUriBase.toString(), it.fingerprint) } else { throw it } @@ -165,46 +168,57 @@ internal class DefaultAuthenticationService @Inject constructor( private suspend fun getLoginFlowInternal(homeServerConnectionConfig: HomeServerConnectionConfig): LoginFlowResult { val authAPI = buildAuthAPI(homeServerConnectionConfig) - // First check the homeserver version - return runCatching { - executeRequest(null) { - authAPI.versions() + // First check if there is a well-known file + return try { + getWellknownLoginFlowInternal(homeServerConnectionConfig) + } catch (failure: Throwable) { + if (failure is Failure.OtherServerError + && failure.httpCode == HttpsURLConnection.HTTP_NOT_FOUND /* 404 */) { + // 404, no well-known data, try direct access to the API + // First check the homeserver version + return runCatching { + executeRequest(null) { + authAPI.versions() + } + } + .map { versions -> + // Ok, it seems that the homeserver url is valid + getLoginFlowResult(authAPI, versions, homeServerConnectionConfig.homeServerUriBase.toString()) + } + .fold( + { + it + }, + { + if (it is Failure.OtherServerError + && it.httpCode == HttpsURLConnection.HTTP_NOT_FOUND /* 404 */) { + // It's maybe a Web client url? + getWebClientDomainLoginFlowInternal(homeServerConnectionConfig) + } else { + throw it + } + } + ) + } else { + throw failure } } - .map { versions -> - // Ok, it seems that the homeserver url is valid - getLoginFlowResult(authAPI, versions, homeServerConnectionConfig.homeServerUri.toString()) - } - .fold( - { - it - }, - { - if (it is Failure.OtherServerError - && it.httpCode == HttpsURLConnection.HTTP_NOT_FOUND /* 404 */) { - // It's maybe a Riot url? - getRiotDomainLoginFlowInternal(homeServerConnectionConfig) - } else { - throw it - } - } - ) } - private suspend fun getRiotDomainLoginFlowInternal(homeServerConnectionConfig: HomeServerConnectionConfig): LoginFlowResult { + private suspend fun getWebClientDomainLoginFlowInternal(homeServerConnectionConfig: HomeServerConnectionConfig): LoginFlowResult { val authAPI = buildAuthAPI(homeServerConnectionConfig) val domain = homeServerConnectionConfig.homeServerUri.host - ?: return getRiotLoginFlowInternal(homeServerConnectionConfig) + ?: return getWebClientLoginFlowInternal(homeServerConnectionConfig) - // Ok, try to get the config.domain.json file of a RiotWeb client + // Ok, try to get the config.domain.json file of a Web client return runCatching { executeRequest(null) { - authAPI.getRiotConfigDomain(domain) + authAPI.getWebClientConfigDomain(domain) } } - .map { riotConfig -> - onRiotConfigRetrieved(homeServerConnectionConfig, riotConfig) + .map { webClientConfig -> + onWebClientConfigRetrieved(homeServerConnectionConfig, webClientConfig) } .fold( { @@ -214,7 +228,7 @@ internal class DefaultAuthenticationService @Inject constructor( if (it is Failure.OtherServerError && it.httpCode == HttpsURLConnection.HTTP_NOT_FOUND /* 404 */) { // Try with config.json - getRiotLoginFlowInternal(homeServerConnectionConfig) + getWebClientLoginFlowInternal(homeServerConnectionConfig) } else { throw it } @@ -222,40 +236,24 @@ internal class DefaultAuthenticationService @Inject constructor( ) } - private suspend fun getRiotLoginFlowInternal(homeServerConnectionConfig: HomeServerConnectionConfig): LoginFlowResult { + private suspend fun getWebClientLoginFlowInternal(homeServerConnectionConfig: HomeServerConnectionConfig): LoginFlowResult { val authAPI = buildAuthAPI(homeServerConnectionConfig) - // Ok, try to get the config.json file of a RiotWeb client - return runCatching { - executeRequest(null) { - authAPI.getRiotConfig() - } + // Ok, try to get the config.json file of a Web client + return executeRequest(null) { + authAPI.getWebClientConfig() } - .map { riotConfig -> - onRiotConfigRetrieved(homeServerConnectionConfig, riotConfig) + .let { webClientConfig -> + onWebClientConfigRetrieved(homeServerConnectionConfig, webClientConfig) } - .fold( - { - it - }, - { - if (it is Failure.OtherServerError - && it.httpCode == HttpsURLConnection.HTTP_NOT_FOUND /* 404 */) { - // Try with wellknown - getWellknownLoginFlowInternal(homeServerConnectionConfig) - } else { - throw it - } - } - ) } - private suspend fun onRiotConfigRetrieved(homeServerConnectionConfig: HomeServerConnectionConfig, riotConfig: RiotConfig): LoginFlowResult { - val defaultHomeServerUrl = riotConfig.getPreferredHomeServerUrl() + private suspend fun onWebClientConfigRetrieved(homeServerConnectionConfig: HomeServerConnectionConfig, webClientConfig: WebClientConfig): LoginFlowResult { + val defaultHomeServerUrl = webClientConfig.getPreferredHomeServerUrl() if (defaultHomeServerUrl?.isNotEmpty() == true) { // Ok, good sign, we got a default hs url val newHomeServerConnectionConfig = homeServerConnectionConfig.copy( - homeServerUri = Uri.parse(defaultHomeServerUrl) + homeServerUriBase = Uri.parse(defaultHomeServerUrl) ) val newAuthAPI = buildAuthAPI(newHomeServerConnectionConfig) @@ -275,15 +273,13 @@ internal class DefaultAuthenticationService @Inject constructor( val domain = homeServerConnectionConfig.homeServerUri.host ?: throw Failure.OtherServerError("", HttpsURLConnection.HTTP_NOT_FOUND /* 404 */) - // Create a fake userId, for the getWellknown task - val fakeUserId = "@alice:$domain" - val wellknownResult = getWellknownTask.execute(GetWellknownTask.Params(fakeUserId, homeServerConnectionConfig)) + val wellknownResult = getWellknownTask.execute(GetWellknownTask.Params(domain, homeServerConnectionConfig)) return when (wellknownResult) { is WellknownResult.Prompt -> { val newHomeServerConnectionConfig = homeServerConnectionConfig.copy( - homeServerUri = Uri.parse(wellknownResult.homeServerUrl), - identityServerUri = wellknownResult.identityServerUrl?.let { Uri.parse(it) } + homeServerUriBase = Uri.parse(wellknownResult.homeServerUrl), + identityServerUri = wellknownResult.identityServerUrl?.let { Uri.parse(it) } ?: homeServerConnectionConfig.identityServerUri ) val newAuthAPI = buildAuthAPI(newHomeServerConnectionConfig) @@ -379,7 +375,14 @@ internal class DefaultAuthenticationService @Inject constructor( override suspend fun getWellKnownData(matrixId: String, homeServerConnectionConfig: HomeServerConnectionConfig?): WellknownResult { - return getWellknownTask.execute(GetWellknownTask.Params(matrixId, homeServerConnectionConfig)) + if (!MatrixPatterns.isUserId(matrixId)) { + throw MatrixIdFailure.InvalidMatrixId + } + + return getWellknownTask.execute(GetWellknownTask.Params( + domain = matrixId.getDomain(), + homeServerConnectionConfig = homeServerConnectionConfig) + ) } override suspend fun directAuthentication(homeServerConnectionConfig: HomeServerConnectionConfig, @@ -390,7 +393,7 @@ internal class DefaultAuthenticationService @Inject constructor( } private fun buildAuthAPI(homeServerConnectionConfig: HomeServerConnectionConfig): AuthAPI { - val retrofit = retrofitFactory.create(buildClient(homeServerConnectionConfig), homeServerConnectionConfig.homeServerUri.toString()) + val retrofit = retrofitFactory.create(buildClient(homeServerConnectionConfig), homeServerConnectionConfig.homeServerUriBase.toString()) return retrofit.create(AuthAPI::class.java) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/IsValidClientServerApiTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/IsValidClientServerApiTask.kt index 867cf46b8d..bc3d887000 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/IsValidClientServerApiTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/IsValidClientServerApiTask.kt @@ -42,7 +42,7 @@ internal class DefaultIsValidClientServerApiTask @Inject constructor( override suspend fun execute(params: IsValidClientServerApiTask.Params): Boolean { val client = buildClient(params.homeServerConnectionConfig) - val homeServerUrl = params.homeServerConnectionConfig.homeServerUri.toString() + val homeServerUrl = params.homeServerConnectionConfig.homeServerUriBase.toString() val authAPI = retrofitFactory.create(client, homeServerUrl) .create(AuthAPI::class.java) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/SessionCreator.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/SessionCreator.kt index 7c4a0c38ec..160fd2d556 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/SessionCreator.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/SessionCreator.kt @@ -38,7 +38,7 @@ internal class DefaultSessionCreator @Inject constructor( ) : SessionCreator { /** - * Credentials can affect the homeServerConnectionConfig, override home server url and/or + * Credentials can affect the homeServerConnectionConfig, override homeserver url and/or * identity server url if provided in the credentials */ override suspend fun createSession(credentials: Credentials, homeServerConnectionConfig: HomeServerConnectionConfig): Session { @@ -56,7 +56,7 @@ internal class DefaultSessionCreator @Inject constructor( tryOrNull { isValidClientServerApiTask.execute( IsValidClientServerApiTask.Params( - homeServerConnectionConfig.copy(homeServerUri = it) + homeServerConnectionConfig.copy(homeServerUriBase = it) ) ) .also { Timber.d("Overriding homeserver url: $it") } @@ -66,7 +66,7 @@ internal class DefaultSessionCreator @Inject constructor( val sessionParams = SessionParams( credentials = credentials, homeServerConnectionConfig = homeServerConnectionConfig.copy( - homeServerUri = overriddenUrl ?: homeServerConnectionConfig.homeServerUri, + homeServerUriBase = overriddenUrl ?: homeServerConnectionConfig.homeServerUriBase, identityServerUri = credentials.discoveryInformation?.identityServer?.baseURL // remove trailing "/" ?.trim { it == '/' } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/RiotConfig.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/WebClientConfig.kt similarity index 84% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/RiotConfig.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/WebClientConfig.kt index e61358a67b..65c3dc64a6 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/RiotConfig.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/WebClientConfig.kt @@ -20,7 +20,7 @@ import com.squareup.moshi.Json import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) -internal data class RiotConfig( +internal data class WebClientConfig( /** * This is now deprecated, but still used first, rather than value from "default_server_config" */ @@ -28,7 +28,7 @@ internal data class RiotConfig( val defaultHomeServerUrl: String?, @Json(name = "default_server_config") - val defaultServerConfig: RiotConfigDefaultServerConfig? + val defaultServerConfig: WebClientConfigDefaultServerConfig? ) { fun getPreferredHomeServerUrl(): String? { return defaultHomeServerUrl @@ -38,13 +38,13 @@ internal data class RiotConfig( } @JsonClass(generateAdapter = true) -internal data class RiotConfigDefaultServerConfig( +internal data class WebClientConfigDefaultServerConfig( @Json(name = "m.homeserver") - val homeServer: RiotConfigBaseConfig? = null + val homeServer: WebClientConfigBaseConfig? = null ) @JsonClass(generateAdapter = true) -internal data class RiotConfigBaseConfig( +internal data class WebClientConfigBaseConfig( @Json(name = "base_url") val baseURL: String? = null ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/AuthRealmMigration.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/AuthRealmMigration.kt index bb2667228b..c2104690b3 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/AuthRealmMigration.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/AuthRealmMigration.kt @@ -16,17 +16,19 @@ package org.matrix.android.sdk.internal.auth.db -import org.matrix.android.sdk.api.auth.data.Credentials -import org.matrix.android.sdk.api.auth.data.sessionId -import org.matrix.android.sdk.internal.di.MoshiProvider +import android.net.Uri import io.realm.DynamicRealm import io.realm.RealmMigration +import org.matrix.android.sdk.api.auth.data.Credentials +import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig +import org.matrix.android.sdk.api.auth.data.sessionId +import org.matrix.android.sdk.internal.di.MoshiProvider import timber.log.Timber internal object AuthRealmMigration : RealmMigration { // Current schema version - const val SCHEMA_VERSION = 3L + const val SCHEMA_VERSION = 4L override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) { Timber.d("Migrating Auth Realm from $oldVersion to $newVersion") @@ -34,6 +36,7 @@ internal object AuthRealmMigration : RealmMigration { if (oldVersion <= 0) migrateTo1(realm) if (oldVersion <= 1) migrateTo2(realm) if (oldVersion <= 2) migrateTo3(realm) + if (oldVersion <= 3) migrateTo4(realm) } private fun migrateTo1(realm: DynamicRealm) { @@ -81,4 +84,34 @@ internal object AuthRealmMigration : RealmMigration { } ?.addPrimaryKey(SessionParamsEntityFields.SESSION_ID) } + + private fun migrateTo4(realm: DynamicRealm) { + Timber.d("Step 3 -> 4") + Timber.d("Update SessionParamsEntity to add HomeServerConnectionConfig.homeServerUriBase value") + + val adapter = MoshiProvider.providesMoshi() + .adapter(HomeServerConnectionConfig::class.java) + + realm.schema.get("SessionParamsEntity") + ?.transform { + val homeserverConnectionConfigJson = it.getString(SessionParamsEntityFields.HOME_SERVER_CONNECTION_CONFIG_JSON) + + val homeserverConnectionConfig = adapter + .fromJson(homeserverConnectionConfigJson) + + val homeserverUrl = homeserverConnectionConfig?.homeServerUri?.toString() + // Special case for matrix.org. Old session may use "https://matrix.org", newer one may use + // "https://matrix-client.matrix.org". So fix that here + val alteredHomeserverConnectionConfig = + if (homeserverUrl == "https://matrix.org" || homeserverUrl == "https://matrix-client.matrix.org") { + homeserverConnectionConfig.copy( + homeServerUri = Uri.parse("https://matrix.org"), + homeServerUriBase = Uri.parse("https://matrix-client.matrix.org") + ) + } else { + homeserverConnectionConfig + } + it.set(SessionParamsEntityFields.HOME_SERVER_CONNECTION_CONFIG_JSON, adapter.toJson(alteredHomeserverConnectionConfig)) + } + } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DirectLoginTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DirectLoginTask.kt index 77bbb8096f..3888633723 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DirectLoginTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DirectLoginTask.kt @@ -50,7 +50,7 @@ internal class DefaultDirectLoginTask @Inject constructor( override suspend fun execute(params: DirectLoginTask.Params): Session { val client = buildClient(params.homeServerConnectionConfig) - val homeServerUrl = params.homeServerConnectionConfig.homeServerUri.toString() + val homeServerUrl = params.homeServerConnectionConfig.homeServerUriBase.toString() val authAPI = retrofitFactory.create(client, homeServerUrl) .create(AuthAPI::class.java) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/CryptoModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/CryptoModule.kt index e114f86a99..84d4fef5af 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/CryptoModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/CryptoModule.kt @@ -112,7 +112,6 @@ internal abstract class CryptoModule { @SessionScope fun providesRealmConfiguration(@SessionFilesDirectory directory: File, @UserMd5 userMd5: String, - realmCryptoStoreMigration: RealmCryptoStoreMigration, realmKeysUtils: RealmKeysUtils): RealmConfiguration { return RealmConfiguration.Builder() .directory(directory) @@ -123,7 +122,7 @@ internal abstract class CryptoModule { .modules(RealmCryptoStoreModule()) .allowWritesOnUiThread(true) .schemaVersion(RealmCryptoStoreMigration.CRYPTO_STORE_SCHEMA_VERSION) - .migration(realmCryptoStoreMigration) + .migration(RealmCryptoStoreMigration) .build() } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DeviceListManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DeviceListManager.kt index 63f15aaf6e..79910c6de2 100755 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DeviceListManager.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DeviceListManager.kt @@ -16,6 +16,7 @@ package org.matrix.android.sdk.internal.crypto +import kotlinx.coroutines.CancellationException import kotlinx.coroutines.launch import org.matrix.android.sdk.api.MatrixPatterns import org.matrix.android.sdk.api.auth.data.Credentials @@ -336,7 +337,12 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM downloadKeysForUsersTask.execute(params) } catch (throwable: Throwable) { Timber.e(throwable, "## CRYPTO | doKeyDownloadForUsers(): error") - onKeysDownloadFailed(filteredUsers) + if (throwable is CancellationException) { + // the crypto module is getting closed, so we cannot access the DB anymore + Timber.w("The crypto module is closed, ignoring this error") + } else { + onKeysDownloadFailed(filteredUsers) + } throw throwable } Timber.v("## CRYPTO | doKeyDownloadForUsers() : Got keys for " + filteredUsers.size + " users") diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/attachments/MXEncryptedAttachments.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/attachments/MXEncryptedAttachments.kt index 5a9852b6db..70730326da 100755 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/attachments/MXEncryptedAttachments.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/attachments/MXEncryptedAttachments.kt @@ -39,7 +39,9 @@ internal object MXEncryptedAttachments { private const val SECRET_KEY_SPEC_ALGORITHM = "AES" private const val MESSAGE_DIGEST_ALGORITHM = "SHA-256" - fun encrypt(clearStream: InputStream, mimetype: String?, outputFile: File, progress: ((current: Int, total: Int) -> Unit)): EncryptedFileInfo { + fun encrypt(clearStream: InputStream, + outputFile: File, + progress: ((current: Int, total: Int) -> Unit)): EncryptedFileInfo { val t0 = System.currentTimeMillis() val secureRandom = SecureRandom() val initVectorBytes = ByteArray(16) { 0.toByte() } @@ -86,7 +88,6 @@ internal object MXEncryptedAttachments { return EncryptedFileInfo( url = null, - mimetype = mimetype, key = EncryptedFileKey( alg = "A256CTR", ext = true, @@ -155,10 +156,9 @@ internal object MXEncryptedAttachments { * Encrypt an attachment stream. * DO NOT USE for big files, it will load all in memory * @param attachmentStream the attachment stream. Will be closed after this method call. - * @param mimetype the mime type * @return the encryption file info */ - fun encryptAttachment(attachmentStream: InputStream, mimetype: String?): EncryptionResult { + fun encryptAttachment(attachmentStream: InputStream): EncryptionResult { val t0 = System.currentTimeMillis() val secureRandom = SecureRandom() @@ -207,7 +207,6 @@ internal object MXEncryptedAttachments { return EncryptionResult( encryptedFileInfo = EncryptedFileInfo( url = null, - mimetype = mimetype, key = EncryptedFileKey( alg = "A256CTR", ext = true, @@ -232,7 +231,9 @@ internal object MXEncryptedAttachments { * @param outputStream the outputStream where the decrypted attachment will be write. * @return true in case of success, false in case of error */ - fun decryptAttachment(attachmentStream: InputStream?, elementToDecrypt: ElementToDecrypt?, outputStream: OutputStream): Boolean { + fun decryptAttachment(attachmentStream: InputStream?, + elementToDecrypt: ElementToDecrypt?, + outputStream: OutputStream): Boolean { // sanity checks if (null == attachmentStream || elementToDecrypt == null) { Timber.e("## decryptAttachment() : null stream") diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/MXDeviceInfo.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/MXDeviceInfo.kt index 00b8bde5d9..68cc41005e 100755 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/MXDeviceInfo.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/MXDeviceInfo.kt @@ -56,7 +56,7 @@ data class MXDeviceInfo( val signatures: Map>? = null, /* - * Additional data from the home server. + * Additional data from the homeserver. */ @Json(name = "unsigned") val unsigned: JsonDict? = null, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/EncryptedFileInfo.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/EncryptedFileInfo.kt index 0ed6c0dac9..4fc3adb42c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/EncryptedFileInfo.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/EncryptedFileInfo.kt @@ -29,12 +29,6 @@ data class EncryptedFileInfo( @Json(name = "url") val url: String? = null, - /** - * Not documented - */ - @Json(name = "mimetype") - val mimetype: String? = null, - /** * Required. A JSON Web Key object. */ diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCryptoStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCryptoStore.kt index 181bd94cc7..3d12e74fcd 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCryptoStore.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCryptoStore.kt @@ -475,7 +475,7 @@ internal interface IMXCryptoStore { fun getGossipingEvents(): List fun setDeviceKeysUploaded(uploaded: Boolean) - fun getDeviceKeysUploaded(): Boolean + fun areDeviceKeysUploaded(): Boolean fun tidyUpDataBase() fun logDbUsageInfo() } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt index 9ae93d61eb..9266f8fe7d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt @@ -937,7 +937,7 @@ internal class RealmCryptoStore @Inject constructor( } } - override fun getDeviceKeysUploaded(): Boolean { + override fun areDeviceKeysUploaded(): Boolean { return doWithRealm(realmConfiguration) { it.where().findFirst()?.deviceKeysSentToServer } ?: false diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStoreMigration.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStoreMigration.kt index bca7914388..8e77f5b823 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStoreMigration.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStoreMigration.kt @@ -18,6 +18,9 @@ package org.matrix.android.sdk.internal.crypto.store.db import com.squareup.moshi.Moshi import com.squareup.moshi.Types +import io.realm.DynamicRealm +import io.realm.RealmMigration +import io.realm.RealmObjectSchema import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.util.JsonDict import org.matrix.android.sdk.internal.crypto.model.MXDeviceInfo @@ -35,29 +38,24 @@ import org.matrix.android.sdk.internal.crypto.store.db.model.KeysBackupDataEntit import org.matrix.android.sdk.internal.crypto.store.db.model.MyDeviceLastSeenInfoEntityFields import org.matrix.android.sdk.internal.crypto.store.db.model.OlmInboundGroupSessionEntityFields import org.matrix.android.sdk.internal.crypto.store.db.model.OlmSessionEntityFields +import org.matrix.android.sdk.internal.crypto.store.db.model.OutboundGroupSessionInfoEntityFields import org.matrix.android.sdk.internal.crypto.store.db.model.OutgoingGossipingRequestEntityFields import org.matrix.android.sdk.internal.crypto.store.db.model.SharedSessionEntityFields import org.matrix.android.sdk.internal.crypto.store.db.model.TrustLevelEntityFields import org.matrix.android.sdk.internal.crypto.store.db.model.UserEntityFields import org.matrix.android.sdk.internal.crypto.store.db.model.WithHeldSessionEntityFields +import org.matrix.android.sdk.internal.di.MoshiProvider import org.matrix.android.sdk.internal.di.SerializeNulls -import io.realm.DynamicRealm -import io.realm.RealmMigration -import io.realm.RealmObjectSchema -import org.matrix.android.sdk.internal.crypto.store.db.model.OutboundGroupSessionInfoEntityFields import org.matrix.androidsdk.crypto.data.MXOlmInboundGroupSession2 import timber.log.Timber -import javax.inject.Inject import org.matrix.androidsdk.crypto.data.MXDeviceInfo as LegacyMXDeviceInfo -internal class RealmCryptoStoreMigration @Inject constructor(private val crossSigningKeysMapper: CrossSigningKeysMapper) : RealmMigration { +internal object RealmCryptoStoreMigration : RealmMigration { - companion object { - // 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 - } + // 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 private fun RealmObjectSchema.addFieldIfNotExists(fieldName: String, fieldType: Class<*>): RealmObjectSchema { if (!hasField(fieldName)) { @@ -384,6 +382,8 @@ internal class RealmCryptoStoreMigration @Inject constructor(private val crossSi private fun migrateTo7(realm: DynamicRealm) { Timber.d("Step 6 -> 7") Timber.d("Updating KeyInfoEntity table") + val crossSigningKeysMapper = CrossSigningKeysMapper(MoshiProvider.providesMoshi()) + val keyInfoEntities = realm.where("KeyInfoEntity").findAll() try { keyInfoEntities.forEach { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/InitializeCrossSigningTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/InitializeCrossSigningTask.kt index f8a8354e48..1d40e5defd 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/InitializeCrossSigningTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/InitializeCrossSigningTask.kt @@ -97,7 +97,7 @@ internal class DefaultInitializeCrossSigningTask @Inject constructor( Timber.v("## CrossSigning - sskPublicKey:$sskPublicKey") - // Sign userSigningKey with master + // Sign selfSigningKey with master val signedSSK = CryptoCrossSigningKey.Builder(userId, KeyUsage.SELF_SIGNING) .key(sskPublicKey) .build() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt index 2b3c3b28ee..28ae4d8bfd 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt @@ -19,9 +19,10 @@ package org.matrix.android.sdk.internal.database import io.realm.DynamicRealm import io.realm.FieldAttribute import io.realm.RealmMigration -import org.matrix.android.sdk.api.session.room.model.VersioningState import org.matrix.android.sdk.api.session.events.model.EventType +import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesContent +import org.matrix.android.sdk.api.session.room.model.VersioningState import org.matrix.android.sdk.api.session.room.model.create.RoomCreateContent import org.matrix.android.sdk.api.session.room.model.tag.RoomTag import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntityFields @@ -40,14 +41,12 @@ import org.matrix.android.sdk.internal.database.model.SpaceChildSummaryEntityFie import org.matrix.android.sdk.internal.database.model.SpaceParentSummaryEntityFields import org.matrix.android.sdk.internal.database.model.TimelineEventEntityFields import org.matrix.android.sdk.internal.di.MoshiProvider +import org.matrix.android.sdk.internal.query.process import timber.log.Timber -import javax.inject.Inject -class RealmSessionStoreMigration @Inject constructor() : RealmMigration { +internal object RealmSessionStoreMigration : RealmMigration { - companion object { - const val SESSION_STORE_SCHEMA_VERSION = 14L - } + const val SESSION_STORE_SCHEMA_VERSION = 16L override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) { Timber.v("Migrating Realm Session from $oldVersion to $newVersion") @@ -66,6 +65,8 @@ class RealmSessionStoreMigration @Inject constructor() : RealmMigration { if (oldVersion <= 11) migrateTo12(realm) if (oldVersion <= 12) migrateTo13(realm) if (oldVersion <= 13) migrateTo14(realm) + if (oldVersion <= 14) migrateTo15(realm) + if (oldVersion <= 15) migrateTo16(realm) } private fun migrateTo1(realm: DynamicRealm) { @@ -292,7 +293,7 @@ class RealmSessionStoreMigration @Inject constructor() : RealmMigration { Timber.d("Step 13 -> 14") val roomAccountDataSchema = realm.schema.create("RoomAccountDataEntity") .addField(RoomAccountDataEntityFields.CONTENT_STR, String::class.java) - .addField(RoomAccountDataEntityFields.TYPE, String::class.java, FieldAttribute.INDEXED) + .addField(RoomAccountDataEntityFields.TYPE, String::class.java, FieldAttribute.INDEXED) realm.schema.get("RoomEntity") ?.addRealmListField(RoomEntityFields.ACCOUNT_DATA.`$`, roomAccountDataSchema) @@ -306,4 +307,27 @@ class RealmSessionStoreMigration @Inject constructor() : RealmMigration { roomAccountDataSchema.isEmbedded = true } + + private fun migrateTo15(realm: DynamicRealm) { + Timber.d("Step 14 -> 15") + // fix issue with flattenParentIds on DM that kept growing with duplicate + // so we reset it, will be updated next sync + realm.where("RoomSummaryEntity") + .process(RoomSummaryEntityFields.MEMBERSHIP_STR, Membership.activeMemberships()) + .equalTo(RoomSummaryEntityFields.IS_DIRECT, true) + .findAll() + .onEach { + it.setString(RoomSummaryEntityFields.FLATTEN_PARENT_IDS, null) + } + } + + private fun migrateTo16(realm: DynamicRealm) { + Timber.d("Step 15 -> 16") + realm.schema.get("HomeServerCapabilitiesEntity") + ?.addField(HomeServerCapabilitiesEntityFields.ROOM_VERSIONS_JSON, String::class.java) + ?.transform { obj -> + // Schedule a refresh of the capabilities + obj.setLong(HomeServerCapabilitiesEntityFields.LAST_UPDATED_TIMESTAMP, 0) + } + } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/SessionRealmConfigurationFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/SessionRealmConfigurationFactory.kt index 244fe3432a..1771c5b202 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/SessionRealmConfigurationFactory.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/SessionRealmConfigurationFactory.kt @@ -43,7 +43,6 @@ internal class SessionRealmConfigurationFactory @Inject constructor( @SessionFilesDirectory val directory: File, @SessionId val sessionId: String, @UserMd5 val userMd5: String, - val migration: RealmSessionStoreMigration, context: Context) { // Keep legacy preferences name for compatibility reason @@ -72,7 +71,7 @@ internal class SessionRealmConfigurationFactory @Inject constructor( .allowWritesOnUiThread(true) .modules(SessionRealmModule()) .schemaVersion(RealmSessionStoreMigration.SESSION_STORE_SCHEMA_VERSION) - .migration(migration) + .migration(RealmSessionStoreMigration) .build() // Try creating a realm instance and if it succeeds we can clear the flag diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/HomeServerCapabilitiesMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/HomeServerCapabilitiesMapper.kt index b18c67294f..2575cdef26 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/HomeServerCapabilitiesMapper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/HomeServerCapabilitiesMapper.kt @@ -16,8 +16,15 @@ 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.RoomVersionCapabilities +import org.matrix.android.sdk.api.session.homeserver.RoomVersionInfo +import org.matrix.android.sdk.api.session.homeserver.RoomVersionStatus import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEntity +import org.matrix.android.sdk.internal.di.MoshiProvider +import org.matrix.android.sdk.internal.session.homeserver.RoomVersions +import org.matrix.android.sdk.internal.session.room.version.DefaultRoomVersionService /** * HomeServerCapabilitiesEntity -> HomeSeverCapabilities @@ -29,7 +36,30 @@ internal object HomeServerCapabilitiesMapper { canChangePassword = entity.canChangePassword, maxUploadFileSize = entity.maxUploadFileSize, lastVersionIdentityServerSupported = entity.lastVersionIdentityServerSupported, - defaultIdentityServerUrl = entity.defaultIdentityServerUrl + defaultIdentityServerUrl = entity.defaultIdentityServerUrl, + roomVersions = mapRoomVersion(entity.roomVersionsJson) ) } + + private fun mapRoomVersion(roomVersionsJson: String?): RoomVersionCapabilities? { + roomVersionsJson ?: return null + + return tryOrNull { + MoshiProvider.providesMoshi().adapter(RoomVersions::class.java).fromJson(roomVersionsJson)?.let { + 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 + } + ) + } + ) + } + } + } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/HomeServerCapabilitiesEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/HomeServerCapabilitiesEntity.kt index 763dcf80a2..980449ddfb 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/HomeServerCapabilitiesEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/HomeServerCapabilitiesEntity.kt @@ -21,6 +21,7 @@ import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities internal open class HomeServerCapabilitiesEntity( var canChangePassword: Boolean = true, + var roomVersionsJson: String? = null, var maxUploadFileSize: Long = HomeServerCapabilities.MAX_UPLOAD_FILE_SIZE_UNKNOWN, var lastVersionIdentityServerSupported: Boolean = false, var defaultIdentityServerUrl: String? = null, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/UserAccountDataEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/UserAccountDataEntity.kt index cfdb84d033..e258c20df5 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/UserAccountDataEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/UserAccountDataEntity.kt @@ -20,7 +20,7 @@ import io.realm.RealmObject import io.realm.annotations.Index /** - * Clients can store custom config data for their account on their HomeServer. + * Clients can store custom config data for their account on their homeserver. * This account data will be synced between different devices and can persist across installations on a particular device. * Users may only view the account data for their own account. * The account_data may be either global or scoped to a particular rooms. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/federation/FederationModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/federation/FederationModule.kt index 320bf1d445..a4eef80c58 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/federation/FederationModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/federation/FederationModule.kt @@ -37,7 +37,8 @@ internal abstract class FederationModule { fun providesFederationAPI(@Unauthenticated okHttpClient: Lazy, sessionParams: SessionParams, retrofitFactory: RetrofitFactory): FederationAPI { - return retrofitFactory.create(okHttpClient, sessionParams.homeServerUrl).create(FederationAPI::class.java) + return retrofitFactory.create(okHttpClient, sessionParams.homeServerUrlBase) + .create(FederationAPI::class.java) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/legacy/DefaultLegacySessionImporter.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/legacy/DefaultLegacySessionImporter.kt index 4586cfea1e..ad2aff4c9d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/legacy/DefaultLegacySessionImporter.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/legacy/DefaultLegacySessionImporter.kt @@ -42,7 +42,6 @@ import org.matrix.android.sdk.internal.legacy.riot.HomeServerConnectionConfig as internal class DefaultLegacySessionImporter @Inject constructor( private val context: Context, private val sessionParamsStore: SessionParamsStore, - private val realmCryptoStoreMigration: RealmCryptoStoreMigration, private val realmKeysUtils: RealmKeysUtils ) : LegacySessionImporter { @@ -172,7 +171,7 @@ internal class DefaultLegacySessionImporter @Inject constructor( .name("crypto_store.realm") .modules(RealmCryptoStoreModule()) .schemaVersion(RealmCryptoStoreMigration.CRYPTO_STORE_SCHEMA_VERSION) - .migration(realmCryptoStoreMigration) + .migration(RealmCryptoStoreMigration) .build() Timber.d("Migration: copy DB to encrypted DB") diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/legacy/riot/Credentials.java b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/legacy/riot/Credentials.java index 6844744044..0ca0c7db85 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/legacy/riot/Credentials.java +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/legacy/riot/Credentials.java @@ -41,7 +41,7 @@ public class Credentials { public String deviceId; - // Optional data that may contain info to override home server and/or identity server + // Optional data that may contain info to override homeserver and/or identity server public WellKnown wellKnown; public JSONObject toJson() throws JSONException { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/legacy/riot/HomeServerConnectionConfig.java b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/legacy/riot/HomeServerConnectionConfig.java index 21d069f295..75fc187c45 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/legacy/riot/HomeServerConnectionConfig.java +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/legacy/riot/HomeServerConnectionConfig.java @@ -44,7 +44,7 @@ import timber.log.Timber; */ public class HomeServerConnectionConfig { - // the home server URI + // the homeserver URI private Uri mHomeServerUri; // the jitsi server URI. Can be null @Nullable @@ -82,7 +82,7 @@ public class HomeServerConnectionConfig { } /** - * Update the home server URI. + * Update the homeserver URI. * * @param uri the new HS uri */ @@ -91,7 +91,7 @@ public class HomeServerConnectionConfig { } /** - * @return the home server uri + * @return the homeserver uri */ public Uri getHomeserverUri() { return mHomeServerUri; @@ -145,7 +145,7 @@ public class HomeServerConnectionConfig { public void setCredentials(Credentials credentials) { mCredentials = credentials; - // Override home server url and/or identity server url if provided + // Override homeserver url and/or identity server url if provided if (credentials.wellKnown != null) { if (credentials.wellKnown.homeServer != null) { String homeServerUrl = credentials.wellKnown.homeServer.baseURL; @@ -200,7 +200,7 @@ public class HomeServerConnectionConfig { } /** - * TLS versions accepted for TLS connections with the home server. + * TLS versions accepted for TLS connections with the homeserver. */ @Nullable public List getAcceptedTlsVersions() { @@ -208,7 +208,7 @@ public class HomeServerConnectionConfig { } /** - * TLS cipher suites accepted for TLS connections with the home server. + * TLS cipher suites accepted for TLS connections with the homeserver. */ @Nullable public List getAcceptedTlsCipherSuites() { @@ -426,7 +426,7 @@ public class HomeServerConnectionConfig { */ public Builder withHomeServerUri(final Uri homeServerUri) { if (homeServerUri == null || (!"http".equals(homeServerUri.getScheme()) && !"https".equals(homeServerUri.getScheme()))) { - throw new RuntimeException("Invalid home server URI: " + homeServerUri); + throw new RuntimeException("Invalid homeserver URI: " + homeServerUri); } // remove trailing / @@ -435,7 +435,7 @@ public class HomeServerConnectionConfig { String url = homeServerUri.toString(); mHomeServerConnectionConfig.mHomeServerUri = Uri.parse(url.substring(0, url.length() - 1)); } catch (Exception e) { - throw new RuntimeException("Invalid home server URI: " + homeServerUri); + throw new RuntimeException("Invalid homeserver URI: " + homeServerUri); } } else { mHomeServerConnectionConfig.mHomeServerUri = homeServerUri; @@ -549,7 +549,7 @@ public class HomeServerConnectionConfig { } /** - * Add an accepted TLS version for TLS connections with the home server. + * Add an accepted TLS version for TLS connections with the homeserver. * * @param tlsVersion the tls version to add to the set of TLS versions accepted. * @return this builder @@ -577,7 +577,7 @@ public class HomeServerConnectionConfig { } /** - * Add a TLS cipher suite to the list of accepted TLS connections with the home server. + * Add a TLS cipher suite to the list of accepted TLS connections with the homeserver. * * @param tlsCipherSuite the tls cipher suite to add. * @return this builder @@ -666,7 +666,7 @@ public class HomeServerConnectionConfig { public HomeServerConnectionConfig build() { // Check mandatory parameters if (mHomeServerConnectionConfig.mHomeServerUri == null) { - throw new RuntimeException("Home server URI not set"); + throw new RuntimeException("Homeserver URI not set"); } return mHomeServerConnectionConfig; diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/legacy/riot/LoginStorage.java b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/legacy/riot/LoginStorage.java index 516007524e..2820b66886 100755 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/legacy/riot/LoginStorage.java +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/legacy/riot/LoginStorage.java @@ -38,7 +38,7 @@ import timber.log.Timber; public class LoginStorage { private static final String PREFS_LOGIN = "Vector.LoginStorage"; - // multi accounts + home server config + // multi accounts + homeserver config private static final String PREFS_KEY_CONNECTION_CONFIGS = "PREFS_KEY_CONNECTION_CONFIGS"; private final Context mContext; @@ -49,7 +49,7 @@ public class LoginStorage { } /** - * @return the list of home server configurations. + * @return the list of homeserver configurations. */ public List getCredentialsList() { SharedPreferences prefs = mContext.getSharedPreferences(PREFS_LOGIN, Context.MODE_PRIVATE); @@ -85,7 +85,7 @@ public class LoginStorage { /** * Add a credentials to the credentials list * - * @param config the home server config to add. + * @param config the homeserver config to add. */ public void addCredentials(HomeServerConnectionConfig config) { if (null != config && config.getCredentials() != null) { @@ -203,4 +203,4 @@ public class LoginStorage { //Need to commit now because called before forcing an app restart editor.commit(); } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ssl/CertUtil.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ssl/CertUtil.kt index 9d7263f56a..976751446b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ssl/CertUtil.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ssl/CertUtil.kt @@ -253,7 +253,7 @@ internal object CertUtil { val list = ArrayList() list.add(builder.build()) // TODO: we should display a warning if user enter an http url - if (hsConfig.allowHttpExtension || hsConfig.homeServerUri.toString().startsWith("http://")) { + if (hsConfig.allowHttpExtension || hsConfig.homeServerUriBase.toString().startsWith("http://")) { list.add(ConnectionSpec.CLEARTEXT) } return list diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/DefaultRawService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/DefaultRawService.kt index 42b826de16..bca1e498de 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/DefaultRawService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/DefaultRawService.kt @@ -29,10 +29,9 @@ internal class DefaultRawService @Inject constructor( return getUrlTask.execute(GetUrlTask.Params(url, cacheStrategy)) } - override suspend fun getWellknown(userId: String): String { - val homeServerDomain = userId.substringAfter(":") + override suspend fun getWellknown(domain: String): String { return getUrl( - "https://$homeServerDomain/.well-known/matrix/client", + "https://$domain/.well-known/matrix/client", CacheStrategy.TtlCache(TimeUnit.HOURS.toMillis(8), false) ) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultFileService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultFileService.kt index a284d976d0..1cbf621d36 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultFileService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultFileService.kt @@ -33,6 +33,7 @@ import org.matrix.android.sdk.internal.di.SessionDownloadsDirectory import org.matrix.android.sdk.internal.di.UnauthenticatedWithCertificateWithProgress import org.matrix.android.sdk.internal.session.download.DownloadProgressInterceptor.Companion.DOWNLOAD_PROGRESS_INTERCEPTOR_HEADER import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers +import org.matrix.android.sdk.internal.util.file.AtomicFileCreator import org.matrix.android.sdk.internal.util.md5 import org.matrix.android.sdk.internal.util.writeToFile import timber.log.Timber @@ -96,6 +97,9 @@ internal class DefaultFileService @Inject constructor( } } + var atomicFileDownload: AtomicFileCreator? = null + var atomicFileDecrypt: AtomicFileCreator? = null + if (existingDownload != null) { // FIXME If the first downloader cancels then we'll unfortunately be cancelled too. return existingDownload.await() @@ -131,8 +135,11 @@ internal class DefaultFileService @Inject constructor( Timber.v("Response size ${response.body?.contentLength()} - Stream available: ${!source.exhausted()}") // Write the file to cache (encrypted version if the file is encrypted) - writeToFile(source.inputStream(), cachedFiles.file) + // Write to a part file first, so if we abort before done, we don't have a broken cached file + val atomicFileCreator = AtomicFileCreator(cachedFiles.file).also { atomicFileDownload = it } + writeToFile(source.inputStream(), atomicFileCreator.partFile) response.close() + atomicFileCreator.commit() } else { Timber.v("## FileService: cache hit for $url") } @@ -145,8 +152,10 @@ internal class DefaultFileService @Inject constructor( Timber.v("## FileService: decrypt file") // Ensure the parent folder exists cachedFiles.decryptedFile.parentFile?.mkdirs() + // Write to a part file first, so if we abort before done, we don't have a broken cached file + val atomicFileCreator = AtomicFileCreator(cachedFiles.decryptedFile).also { atomicFileDecrypt = it } val decryptSuccess = cachedFiles.file.inputStream().use { inputStream -> - cachedFiles.decryptedFile.outputStream().buffered().use { outputStream -> + atomicFileCreator.partFile.outputStream().buffered().use { outputStream -> MXEncryptedAttachments.decryptAttachment( inputStream, elementToDecrypt, @@ -154,6 +163,7 @@ internal class DefaultFileService @Inject constructor( ) } } + atomicFileCreator.commit() if (!decryptSuccess) { throw IllegalStateException("Decryption error") } @@ -174,6 +184,11 @@ internal class DefaultFileService @Inject constructor( } toNotify?.completeWith(result) + result.onFailure { + atomicFileDownload?.cancel() + atomicFileDecrypt?.cancel() + } + return result.getOrThrow() } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt index 1cf99bbbd7..c2bd1e24ed 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt @@ -313,7 +313,7 @@ internal class DefaultSession @Inject constructor( override fun getUiaSsoFallbackUrl(authenticationSessionId: String): String { val hsBas = sessionParams.homeServerConnectionConfig - .homeServerUri + .homeServerUriBase .toString() .trim { it == '/' } return buildString { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt index 964620c316..07ba8eb58f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt @@ -260,7 +260,7 @@ internal abstract class SessionModule { sessionParams: SessionParams, retrofitFactory: RetrofitFactory): Retrofit { return retrofitFactory - .create(okHttpClient, sessionParams.homeServerConnectionConfig.homeServerUri.toString()) + .create(okHttpClient, sessionParams.homeServerConnectionConfig.homeServerUriBase.toString()) } @JvmStatic diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallEventProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallEventProcessor.kt index 473adeb8d2..bdc254fc99 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallEventProcessor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallEventProcessor.kt @@ -20,11 +20,14 @@ import io.realm.Realm import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.internal.database.model.EventInsertType +import org.matrix.android.sdk.api.logger.LoggerTag import org.matrix.android.sdk.internal.session.EventInsertLiveProcessor import org.matrix.android.sdk.internal.session.SessionScope import timber.log.Timber import javax.inject.Inject +private val loggerTag = LoggerTag("CallEventProcessor", LoggerTag.VOIP) + @SessionScope internal class CallEventProcessor @Inject constructor(private val callSignalingHandler: CallSignalingHandler) : EventInsertLiveProcessor { @@ -71,14 +74,8 @@ internal class CallEventProcessor @Inject constructor(private val callSignalingH } private fun dispatchToCallSignalingHandlerIfNeeded(event: Event) { - val now = System.currentTimeMillis() event.roomId ?: return Unit.also { - Timber.w("Event with no room id ${event.eventId}") - } - val age = now - (event.ageLocalTs ?: now) - if (age > 40_000) { - // Too old to ring? - return + Timber.tag(loggerTag.value).w("Event with no room id ${event.eventId}") } callSignalingHandler.onCallEvent(event) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallSignalingHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallSignalingHandler.kt index b0901af719..59058bf976 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallSignalingHandler.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallSignalingHandler.kt @@ -16,6 +16,7 @@ package org.matrix.android.sdk.internal.session.call +import org.matrix.android.sdk.api.logger.LoggerTag import org.matrix.android.sdk.api.session.call.CallListener import org.matrix.android.sdk.api.session.call.CallState import org.matrix.android.sdk.api.session.call.MxCall @@ -36,6 +37,9 @@ import org.matrix.android.sdk.internal.session.SessionScope import timber.log.Timber import javax.inject.Inject +private val loggerTag = LoggerTag("CallSignalingHandler", LoggerTag.VOIP) +private const val MAX_AGE_TO_RING = 40_000 + @SessionScope internal class CallSignalingHandler @Inject constructor(private val activeCallHandler: ActiveCallHandler, private val mxCallFactory: MxCallFactory, @@ -111,12 +115,12 @@ internal class CallSignalingHandler @Inject constructor(private val activeCallHa return } if (call.isOutgoing) { - Timber.v("Got selectAnswer for an outbound call: ignoring") + Timber.tag(loggerTag.value).v("Got selectAnswer for an outbound call: ignoring") return } val selectedPartyId = content.selectedPartyId if (selectedPartyId == null) { - Timber.w("Got nonsensical select_answer with null selected_party_id: ignoring") + Timber.tag(loggerTag.value).w("Got nonsensical select_answer with null selected_party_id: ignoring") return } callListenersDispatcher.onCallSelectAnswerReceived(content) @@ -130,7 +134,7 @@ internal class CallSignalingHandler @Inject constructor(private val activeCallHa return } if (call.opponentPartyId != null && !call.partyIdsMatches(content)) { - Timber.v("Ignoring candidates from party ID ${content.partyId} we have chosen party ID ${call.opponentPartyId}") + Timber.tag(loggerTag.value).v("Ignoring candidates from party ID ${content.partyId} we have chosen party ID ${call.opponentPartyId}") return } callListenersDispatcher.onCallIceCandidateReceived(call, content) @@ -163,10 +167,10 @@ internal class CallSignalingHandler @Inject constructor(private val activeCallHa // party ID must match (our chosen partner hanging up the call) or be undefined (we haven't chosen // a partner yet but we're treating the hangup as a reject as per VoIP v0) if (call.opponentPartyId != null && !call.partyIdsMatches(content)) { - Timber.v("Ignoring hangup from party ID ${content.partyId} we have chosen party ID ${call.opponentPartyId}") + Timber.tag(loggerTag.value).v("Ignoring hangup from party ID ${content.partyId} we have chosen party ID ${call.opponentPartyId}") return } - if (call.state != CallState.Terminated) { + if (call.state !is CallState.Ended) { activeCallHandler.removeCall(content.callId) callListenersDispatcher.onCallHangupReceived(content) } @@ -180,12 +184,18 @@ internal class CallSignalingHandler @Inject constructor(private val activeCallHa if (event.roomId == null || event.senderId == null) { return } + val now = System.currentTimeMillis() + val age = now - (event.ageLocalTs ?: now) + if (age > MAX_AGE_TO_RING) { + Timber.tag(loggerTag.value).w("Call invite is too old to ring.") + return + } val content = event.getClearContent().toModel() ?: return content.callId ?: return if (invitedCallIds.contains(content.callId)) { // Call is already known, maybe due to fast lane. Ignore - Timber.d("Ignoring already known call invite") + Timber.tag(loggerTag.value).d("Ignoring already known call invite") return } val incomingCall = mxCallFactory.createIncomingCall( @@ -214,7 +224,8 @@ internal class CallSignalingHandler @Inject constructor(private val activeCallHa callListenersDispatcher.onCallManagedByOtherSession(content.callId) } else { if (call.opponentPartyId != null) { - Timber.v("Ignoring answer from party ID ${content.partyId} we already have an answer from ${call.opponentPartyId}") + Timber.tag(loggerTag.value) + .v("Ignoring answer from party ID ${content.partyId} we already have an answer from ${call.opponentPartyId}") return } mxCallFactory.updateOutgoingCallWithOpponentData(call, event.senderId, content, content.capabilities) @@ -231,7 +242,7 @@ internal class CallSignalingHandler @Inject constructor(private val activeCallHa activeCallHandler.getCallWithId(it) } if (currentCall == null) { - Timber.v("Call with id $callId is null") + Timber.tag(loggerTag.value).v("Call with id $callId is null") } return currentCall } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/DefaultCallSignalingService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/DefaultCallSignalingService.kt index da1f84cc89..4a949e21a6 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/DefaultCallSignalingService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/DefaultCallSignalingService.kt @@ -21,7 +21,6 @@ import org.matrix.android.sdk.api.session.call.CallSignalingService import org.matrix.android.sdk.api.session.call.MxCall import org.matrix.android.sdk.api.session.call.TurnServerResponse import org.matrix.android.sdk.internal.session.SessionScope -import timber.log.Timber import javax.inject.Inject @SessionScope @@ -51,7 +50,6 @@ internal class DefaultCallSignalingService @Inject constructor( } override fun getCallWithId(callId: String): MxCall? { - Timber.v("## VOIP getCallWithId $callId all calls ${activeCallHandler.getActiveCallsLiveData().value?.map { it.callId }}") return activeCallHandler.getCallWithId(callId) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/model/MxCallImpl.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/model/MxCallImpl.kt index f101685a4b..9fc84e6fe5 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/model/MxCallImpl.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/model/MxCallImpl.kt @@ -17,6 +17,7 @@ package org.matrix.android.sdk.internal.session.call.model import org.matrix.android.sdk.api.MatrixConfiguration +import org.matrix.android.sdk.api.logger.LoggerTag import org.matrix.android.sdk.api.session.call.CallIdGenerator import org.matrix.android.sdk.api.session.call.CallState import org.matrix.android.sdk.api.session.call.MxCall @@ -38,6 +39,7 @@ import org.matrix.android.sdk.api.session.room.model.call.CallRejectContent import org.matrix.android.sdk.api.session.room.model.call.CallReplacesContent import org.matrix.android.sdk.api.session.room.model.call.CallSelectAnswerContent import org.matrix.android.sdk.api.session.room.model.call.CallSignalingContent +import org.matrix.android.sdk.api.session.room.model.call.EndCallReason import org.matrix.android.sdk.api.session.room.model.call.SdpType import org.matrix.android.sdk.api.util.Optional import org.matrix.android.sdk.internal.session.call.DefaultCallSignalingService @@ -47,6 +49,8 @@ import org.matrix.android.sdk.internal.session.room.send.queue.EventSenderProces import timber.log.Timber import java.math.BigDecimal +private val loggerTag = LoggerTag("MxCallImpl", LoggerTag.VOIP) + internal class MxCallImpl( override val callId: String, override val isOutgoing: Boolean, @@ -93,7 +97,7 @@ internal class MxCallImpl( try { it.onStateUpdate(this) } catch (failure: Throwable) { - Timber.d("dispatchStateChange failed for call $callId : ${failure.localizedMessage}") + Timber.tag(loggerTag.value).d("dispatchStateChange failed for call $callId : ${failure.localizedMessage}") } } } @@ -109,7 +113,7 @@ internal class MxCallImpl( override fun offerSdp(sdpString: String) { if (!isOutgoing) return - Timber.v("## VOIP offerSdp $callId") + Timber.tag(loggerTag.value).v("offerSdp $callId") state = CallState.Dialing CallInviteContent( callId = callId, @@ -124,7 +128,7 @@ internal class MxCallImpl( } override fun sendLocalCallCandidates(candidates: List) { - Timber.v("Send local call canditates $callId: $candidates") + Timber.tag(loggerTag.value).v("Send local call canditates $callId: $candidates") CallCandidatesContent( callId = callId, partyId = ourPartyId, @@ -141,11 +145,11 @@ internal class MxCallImpl( override fun reject() { if (opponentVersion < 1) { - Timber.v("Opponent version is less than 1 ($opponentVersion): sending hangup instead of reject") - hangUp() + Timber.tag(loggerTag.value).v("Opponent version is less than 1 ($opponentVersion): sending hangup instead of reject") + hangUp(EndCallReason.USER_HANGUP) return } - Timber.v("## VOIP reject $callId") + Timber.tag(loggerTag.value).v("reject $callId") CallRejectContent( callId = callId, partyId = ourPartyId, @@ -153,24 +157,24 @@ internal class MxCallImpl( ) .let { createEventAndLocalEcho(type = EventType.CALL_REJECT, roomId = roomId, content = it.toContent()) } .also { eventSenderProcessor.postEvent(it) } - state = CallState.Terminated + state = CallState.Ended(reason = EndCallReason.USER_HANGUP) } - override fun hangUp(reason: CallHangupContent.Reason?) { - Timber.v("## VOIP hangup $callId") + override fun hangUp(reason: EndCallReason?) { + Timber.tag(loggerTag.value).v("hangup $callId") CallHangupContent( callId = callId, partyId = ourPartyId, - reason = reason ?: CallHangupContent.Reason.USER_HANGUP, + reason = reason, version = MxCall.VOIP_PROTO_VERSION.toString() ) .let { createEventAndLocalEcho(type = EventType.CALL_HANGUP, roomId = roomId, content = it.toContent()) } .also { eventSenderProcessor.postEvent(it) } - state = CallState.Terminated + state = CallState.Ended(reason) } override fun accept(sdpString: String) { - Timber.v("## VOIP accept $callId") + Timber.tag(loggerTag.value).v("accept $callId") if (isOutgoing) return state = CallState.Answering CallAnswerContent( @@ -185,7 +189,7 @@ internal class MxCallImpl( } override fun negotiate(sdpString: String, type: SdpType) { - Timber.v("## VOIP negotiate $callId") + Timber.tag(loggerTag.value).v("negotiate $callId") CallNegotiateContent( callId = callId, partyId = ourPartyId, @@ -198,7 +202,7 @@ internal class MxCallImpl( } override fun selectAnswer() { - Timber.v("## VOIP select answer $callId") + Timber.tag(loggerTag.value).v("select answer $callId") if (isOutgoing) return state = CallState.Answering CallSelectAnswerContent( @@ -219,7 +223,7 @@ internal class MxCallImpl( val profileInfo = try { getProfileInfoTask.execute(profileInfoParams) } catch (failure: Throwable) { - Timber.v("Fail fetching profile info of $targetUserId while transferring call") + Timber.tag(loggerTag.value).v("Fail fetching profile info of $targetUserId while transferring call") null } CallReplacesContent( diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/DefaultContentUrlResolver.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/DefaultContentUrlResolver.kt index f765056496..e4efdaa254 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/DefaultContentUrlResolver.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/DefaultContentUrlResolver.kt @@ -26,7 +26,7 @@ private const val MATRIX_CONTENT_URI_SCHEME = "mxc://" internal class DefaultContentUrlResolver @Inject constructor(homeServerConnectionConfig: HomeServerConnectionConfig) : ContentUrlResolver { - private val baseUrl = homeServerConnectionConfig.homeServerUri.toString().ensureTrailingSlash() + private val baseUrl = homeServerConnectionConfig.homeServerUriBase.toString().ensureTrailingSlash() override val uploadUrl = baseUrl + NetworkConstants.URI_API_MEDIA_PREFIX_PATH_R0 + "upload" diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/UploadContentWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/UploadContentWorker.kt index 237411db53..f14c85cf80 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/UploadContentWorker.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/UploadContentWorker.kt @@ -234,7 +234,7 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter .also { filesToDelete.add(it) } uploadedFileEncryptedFileInfo = - MXEncryptedAttachments.encrypt(fileToUpload.inputStream(), attachment.getSafeMimeType(), encryptedFile) { read, total -> + MXEncryptedAttachments.encrypt(fileToUpload.inputStream(), encryptedFile) { read, total -> notifyTracker(params) { contentUploadStateTracker.setEncrypting(it, read.toLong(), total.toLong()) } @@ -315,7 +315,7 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter if (params.isEncrypted) { Timber.v("Encrypt thumbnail") notifyTracker(params) { contentUploadStateTracker.setEncryptingThumbnail(it) } - val encryptionResult = MXEncryptedAttachments.encryptAttachment(thumbnailData.bytes.inputStream(), thumbnailData.mimeType) + val encryptionResult = MXEncryptedAttachments.encryptAttachment(thumbnailData.bytes.inputStream()) val contentUploadResponse = fileUploader.uploadByteArray( byteArray = encryptionResult.encryptedByteArray, filename = null, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/DefaultHomeServerCapabilitiesService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/DefaultHomeServerCapabilitiesService.kt index 0ed690d972..4c755b54b5 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/DefaultHomeServerCapabilitiesService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/DefaultHomeServerCapabilitiesService.kt @@ -16,18 +16,12 @@ package org.matrix.android.sdk.internal.session.homeserver -import com.zhuinden.monarchy.Monarchy -import io.realm.Realm import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilitiesService -import org.matrix.android.sdk.internal.database.mapper.HomeServerCapabilitiesMapper -import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEntity -import org.matrix.android.sdk.internal.database.query.get -import org.matrix.android.sdk.internal.di.SessionDatabase import javax.inject.Inject internal class DefaultHomeServerCapabilitiesService @Inject constructor( - @SessionDatabase private val monarchy: Monarchy, + private val homeServerCapabilitiesDataSource: HomeServerCapabilitiesDataSource, private val getHomeServerCapabilitiesTask: GetHomeServerCapabilitiesTask ) : HomeServerCapabilitiesService { @@ -36,11 +30,7 @@ internal class DefaultHomeServerCapabilitiesService @Inject constructor( } override fun getHomeServerCapabilities(): HomeServerCapabilities { - return Realm.getInstance(monarchy.realmConfiguration).use { realm -> - HomeServerCapabilitiesEntity.get(realm)?.let { - HomeServerCapabilitiesMapper.map(it) - } - } + return homeServerCapabilitiesDataSource.getHomeServerCapabilities() ?: HomeServerCapabilities() } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetCapabilitiesResult.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetCapabilitiesResult.kt index ab029a0fce..c4bc09a233 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetCapabilitiesResult.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetCapabilitiesResult.kt @@ -19,6 +19,7 @@ package org.matrix.android.sdk.internal.session.homeserver import com.squareup.moshi.Json import com.squareup.moshi.JsonClass import org.matrix.android.sdk.api.extensions.orTrue +import org.matrix.android.sdk.api.util.JsonDict /** * Ref: https://matrix.org/docs/spec/client_server/latest#get-matrix-client-r0-capabilities @@ -38,9 +39,14 @@ internal data class Capabilities( * Capability to indicate if the user can change their password. */ @Json(name = "m.change_password") - val changePassword: ChangePassword? = null + val changePassword: ChangePassword? = null, - // No need for m.room_versions for the moment + /** + * This capability describes the default and available room versions a server supports, and at what level of stability. + * Clients should make use of this capability to determine if users need to be encouraged to upgrade their rooms. + */ + @Json(name = "m.room_versions") + val roomVersions: RoomVersions? = null ) @JsonClass(generateAdapter = true) @@ -52,6 +58,21 @@ internal data class ChangePassword( val enabled: Boolean? ) +@JsonClass(generateAdapter = true) +internal data class RoomVersions( + /** + * Required. The default room version the server is using for new rooms. + */ + @Json(name = "default") + val default: String?, + + /** + * Required. A detailed description of the room versions the server supports. + */ + @Json(name = "available") + val available: JsonDict +) + // The spec says: If not present, the client should assume that password changes are possible via the API internal fun GetCapabilitiesResult.canChangePassword(): Boolean { return capabilities?.changePassword?.enabled.orTrue() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetHomeServerCapabilitiesTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetHomeServerCapabilitiesTask.kt index 740370123f..612b98f863 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetHomeServerCapabilitiesTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetHomeServerCapabilitiesTask.kt @@ -17,6 +17,7 @@ package org.matrix.android.sdk.internal.session.homeserver import com.zhuinden.monarchy.Monarchy +import org.matrix.android.sdk.api.MatrixPatterns.getDomain import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig import org.matrix.android.sdk.api.auth.wellknown.WellknownResult import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities @@ -24,6 +25,7 @@ import org.matrix.android.sdk.internal.auth.version.Versions import org.matrix.android.sdk.internal.auth.version.isLoginAndRegistrationSupportedBySdk import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEntity import org.matrix.android.sdk.internal.database.query.getOrCreate +import org.matrix.android.sdk.internal.di.MoshiProvider import org.matrix.android.sdk.internal.di.SessionDatabase import org.matrix.android.sdk.internal.di.UserId import org.matrix.android.sdk.internal.network.GlobalErrorReceiver @@ -89,7 +91,10 @@ internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor( }.getOrNull() val wellknownResult = runCatching { - getWellknownTask.execute(GetWellknownTask.Params(userId, homeServerConnectionConfig)) + getWellknownTask.execute(GetWellknownTask.Params( + domain = userId.getDomain(), + homeServerConnectionConfig = homeServerConnectionConfig + )) }.getOrNull() insertInDb(capabilities, mediaConfig, versions, wellknownResult) @@ -104,6 +109,10 @@ internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor( if (getCapabilitiesResult != null) { homeServerCapabilitiesEntity.canChangePassword = getCapabilitiesResult.canChangePassword() + + homeServerCapabilitiesEntity.roomVersionsJson = getCapabilitiesResult.capabilities?.roomVersions?.let { + MoshiProvider.providesMoshi().adapter(RoomVersions::class.java).toJson(it) + } } if (getMediaConfigResult != null) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/HomeServerCapabilitiesDataSource.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/HomeServerCapabilitiesDataSource.kt new file mode 100644 index 0000000000..6c913fa41e --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/HomeServerCapabilitiesDataSource.kt @@ -0,0 +1,38 @@ +/* + * 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.homeserver + +import com.zhuinden.monarchy.Monarchy +import io.realm.Realm +import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities +import org.matrix.android.sdk.internal.database.mapper.HomeServerCapabilitiesMapper +import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEntity +import org.matrix.android.sdk.internal.database.query.get +import org.matrix.android.sdk.internal.di.SessionDatabase +import javax.inject.Inject + +internal class HomeServerCapabilitiesDataSource @Inject constructor( + @SessionDatabase private val monarchy: Monarchy +) { + fun getHomeServerCapabilities(): HomeServerCapabilities? { + return Realm.getInstance(monarchy.realmConfiguration).use { realm -> + HomeServerCapabilitiesEntity.get(realm)?.let { + HomeServerCapabilitiesMapper.map(it) + } + } + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/DefaultIdentityService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/DefaultIdentityService.kt index 4f88d8eb95..48870b86b7 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/DefaultIdentityService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/DefaultIdentityService.kt @@ -191,7 +191,7 @@ internal class DefaultIdentityService @Inject constructor( } else { // Disconnect previous one if any, first, because the token will change. // In case of error when configuring the new identity server, this is not a big deal, - // we will ask for a new token on the previous Identity server + // we will ask for a new token on the previous identity server runCatching { identityDisconnectTask.execute(Unit) } .onFailure { Timber.w(it, "Unable to disconnect identity server") } @@ -241,7 +241,7 @@ internal class DefaultIdentityService @Inject constructor( override suspend fun getShareStatus(threePids: List): Map { // Note: we do not require user consent here, because it is used for emails and phone numbers that the user has already sent - // to the home server, and not emails and phone numbers from the contact book of the user + // to the homeserver, and not emails and phone numbers from the contact book of the user if (threePids.isEmpty()) { return emptyMap() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityAuthAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityAuthAPI.kt index 9d990d4d8f..f77eb296aa 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityAuthAPI.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityAuthAPI.kt @@ -42,7 +42,7 @@ internal interface IdentityAuthAPI { suspend fun ping() /** - * Ping v1 will be used to check outdated Identity server + * Ping v1 will be used to check outdated identity server */ @GET("_matrix/identity/api/v1") suspend fun pingV1() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityModule.kt index 7a39a333a5..4d664b76be 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityModule.kt @@ -60,7 +60,6 @@ internal abstract class IdentityModule { @SessionScope fun providesIdentityRealmConfiguration(realmKeysUtils: RealmKeysUtils, @SessionFilesDirectory directory: File, - migration: RealmIdentityStoreMigration, @UserMd5 userMd5: String): RealmConfiguration { return RealmConfiguration.Builder() .directory(directory) @@ -69,7 +68,7 @@ internal abstract class IdentityModule { realmKeysUtils.configureEncryption(this, SessionModule.getKeyAlias(userMd5)) } .schemaVersion(RealmIdentityStoreMigration.IDENTITY_STORE_SCHEMA_VERSION) - .migration(migration) + .migration(RealmIdentityStoreMigration) .allowWritesOnUiThread(true) .modules(IdentityRealmModule()) .build() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/RealmIdentityStoreMigration.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/RealmIdentityStoreMigration.kt index 6081dbab12..21c0f8eb9e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/RealmIdentityStoreMigration.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/RealmIdentityStoreMigration.kt @@ -19,13 +19,10 @@ package org.matrix.android.sdk.internal.session.identity.db import io.realm.DynamicRealm import io.realm.RealmMigration import timber.log.Timber -import javax.inject.Inject -internal class RealmIdentityStoreMigration @Inject constructor() : RealmMigration { +internal object RealmIdentityStoreMigration : RealmMigration { - companion object { - const val IDENTITY_STORE_SCHEMA_VERSION = 1L - } + const val IDENTITY_STORE_SCHEMA_VERSION = 1L override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) { Timber.v("Migrating Realm Identity from $oldVersion to $newVersion") diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/integrationmanager/IntegrationManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/integrationmanager/IntegrationManager.kt index aa82cf9222..b654b8610d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/integrationmanager/IntegrationManager.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/integrationmanager/IntegrationManager.kt @@ -43,8 +43,8 @@ import javax.inject.Inject /** * The integration manager allows to - * - Get the Integration Manager that a user has explicitly set for its account (via account data) - * - Get the recommended/preferred Integration Manager list as defined by the HomeServer (via wellknown) + * - Get the integration manager that a user has explicitly set for its account (via account data) + * - Get the recommended/preferred integration manager list as defined by the homeserver (via wellknown) * - Check if the user has disabled the integration manager feature * - Allow / Disallow Integration manager (propagated to other riot clients) * diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/ViaParameterFinder.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/ViaParameterFinder.kt index 72fbfcced5..82565d8118 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/ViaParameterFinder.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/ViaParameterFinder.kt @@ -16,6 +16,7 @@ package org.matrix.android.sdk.internal.session.permalinks +import org.matrix.android.sdk.api.MatrixPatterns.getDomain 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.internal.di.UserId @@ -47,9 +48,9 @@ internal class ViaParameterFinder @Inject constructor( } fun computeViaParams(userId: String, roomId: String, max: Int): List { - val userHomeserver = userId.substringAfter(":") + val userHomeserver = userId.getDomain() return getUserIdsOfJoinedMembers(roomId) - .map { it.substringAfter(":") } + .map { it.getDomain() } .groupBy { it } .mapValues { it.value.size } .toMutableMap() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/ProfileAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/ProfileAPI.kt index 485a4973ca..4b56db9f13 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/ProfileAPI.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/ProfileAPI.kt @@ -86,7 +86,7 @@ internal interface ProfileAPI { suspend fun addMsisdn(@Body body: AddMsisdnBody): AddMsisdnResponse /** - * Validate Msisdn code (same model than for Identity server API) + * Validate Msisdn code (same model than for identity server API) */ @POST suspend fun validateMsisdn(@Url url: String, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoom.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoom.kt index 0d9c106d41..8afd690f64 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoom.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoom.kt @@ -37,6 +37,7 @@ import org.matrix.android.sdk.api.session.room.tags.TagsService import org.matrix.android.sdk.api.session.room.timeline.TimelineService import org.matrix.android.sdk.api.session.room.typing.TypingService import org.matrix.android.sdk.api.session.room.uploads.UploadsService +import org.matrix.android.sdk.api.session.room.version.RoomVersionService import org.matrix.android.sdk.api.session.search.SearchResult import org.matrix.android.sdk.api.session.space.Space import org.matrix.android.sdk.api.util.Optional @@ -67,9 +68,11 @@ internal class DefaultRoom(override val roomId: String, private val roomMembersService: MembershipService, private val roomPushRuleService: RoomPushRuleService, private val roomAccountDataService: RoomAccountDataService, + private val roomVersionService: RoomVersionService, private val sendStateTask: SendStateTask, private val viaParameterFinder: ViaParameterFinder, - private val searchTask: SearchTask) : + private val searchTask: SearchTask +) : Room, TimelineService by timelineService, SendService by sendService, @@ -85,7 +88,8 @@ internal class DefaultRoom(override val roomId: String, RelationService by relationService, MembershipService by roomMembersService, RoomPushRuleService by roomPushRuleService, - RoomAccountDataService by roomAccountDataService { + RoomAccountDataService by roomAccountDataService, + RoomVersionService by roomVersionService { override fun getRoomSummaryLive(): LiveData> { return roomSummaryDataSource.getRoomSummaryLive(roomId) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt index 4f12604039..18ece60629 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt @@ -369,4 +369,15 @@ internal interface RoomAPI { @Path("roomId") roomId: String, @Path("type") type: String, @Body content: JsonDict) + + /** + * Upgrades the given room to a particular room version. + * Errors: + * 400, The request was invalid. One way this can happen is if the room version requested is not supported by the homeserver + * (M_UNSUPPORTED_ROOM_VERSION) + * 403: The user is not permitted to upgrade the room.(M_FORBIDDEN) + */ + @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/upgrade") + suspend fun upgradeRoom(@Path("roomId") roomId: String, + @Body body: RoomUpgradeBody): RoomUpgradeResponse } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomFactory.kt index 9ddb8f1177..d44eb32529 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomFactory.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomFactory.kt @@ -37,6 +37,7 @@ import org.matrix.android.sdk.internal.session.room.tags.DefaultTagsService import org.matrix.android.sdk.internal.session.room.timeline.DefaultTimelineService import org.matrix.android.sdk.internal.session.room.typing.DefaultTypingService import org.matrix.android.sdk.internal.session.room.uploads.DefaultUploadsService +import org.matrix.android.sdk.internal.session.room.version.DefaultRoomVersionService import org.matrix.android.sdk.internal.session.search.SearchTask import javax.inject.Inject @@ -61,6 +62,7 @@ internal class DefaultRoomFactory @Inject constructor(private val cryptoService: private val relationServiceFactory: DefaultRelationService.Factory, private val membershipServiceFactory: DefaultMembershipService.Factory, private val roomPushRuleServiceFactory: DefaultRoomPushRuleService.Factory, + private val roomVersionServiceFactory: DefaultRoomVersionService.Factory, private val roomAccountDataServiceFactory: DefaultRoomAccountDataService.Factory, private val sendStateTask: SendStateTask, private val viaParameterFinder: ViaParameterFinder, @@ -87,6 +89,7 @@ internal class DefaultRoomFactory @Inject constructor(private val cryptoService: roomMembersService = membershipServiceFactory.create(roomId), roomPushRuleService = roomPushRuleServiceFactory.create(roomId), roomAccountDataService = roomAccountDataServiceFactory.create(roomId), + roomVersionService = roomVersionServiceFactory.create(roomId), sendStateTask = sendStateTask, searchTask = searchTask, viaParameterFinder = viaParameterFinder diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt index d88c195056..c04c899e18 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt @@ -92,6 +92,8 @@ import org.matrix.android.sdk.internal.session.room.typing.DefaultSendTypingTask import org.matrix.android.sdk.internal.session.room.typing.SendTypingTask import org.matrix.android.sdk.internal.session.room.uploads.DefaultGetUploadsTask import org.matrix.android.sdk.internal.session.room.uploads.GetUploadsTask +import org.matrix.android.sdk.internal.session.room.version.DefaultRoomVersionUpgradeTask +import org.matrix.android.sdk.internal.session.room.version.RoomVersionUpgradeTask import org.matrix.android.sdk.internal.session.space.DefaultSpaceService import retrofit2.Retrofit @@ -243,4 +245,7 @@ internal abstract class RoomModule { @Binds abstract fun bindGetEventTask(task: DefaultGetEventTask): GetEventTask + + @Binds + abstract fun bindRoomVersionUpgradeTask(task: DefaultRoomVersionUpgradeTask): RoomVersionUpgradeTask } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomUpgradeBody.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomUpgradeBody.kt new file mode 100644 index 0000000000..4629f6e409 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomUpgradeBody.kt @@ -0,0 +1,26 @@ +/* + * Copyright 2021 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.session.room + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +internal data class RoomUpgradeBody( + @Json(name = "new_version") + val newVersion: String +) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomUpgradeResponse.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomUpgradeResponse.kt new file mode 100644 index 0000000000..1cca2c572b --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomUpgradeResponse.kt @@ -0,0 +1,26 @@ +/* + * Copyright 2021 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.session.room + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +internal data class RoomUpgradeResponse( + @Json(name = "replacement_room") + val replacementRoomId: String +) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/RoomAliasAvailabilityChecker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/RoomAliasAvailabilityChecker.kt index 66164c5280..7c137a8102 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/RoomAliasAvailabilityChecker.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/RoomAliasAvailabilityChecker.kt @@ -16,6 +16,7 @@ package org.matrix.android.sdk.internal.session.room.alias +import org.matrix.android.sdk.api.MatrixPatterns.getDomain import org.matrix.android.sdk.api.failure.Failure import org.matrix.android.sdk.api.session.room.alias.RoomAliasError import org.matrix.android.sdk.internal.di.UserId @@ -64,6 +65,6 @@ internal class RoomAliasAvailabilityChecker @Inject constructor( } companion object { - internal fun String.toFullLocalAlias(userId: String) = "#" + this + ":" + userId.substringAfter(":") + internal fun String.toFullLocalAlias(userId: String) = "#" + this + ":" + userId.getDomain() } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBodyBuilder.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBodyBuilder.kt index 018b865388..2c04759b22 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBodyBuilder.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBodyBuilder.kt @@ -59,7 +59,7 @@ internal class CreateRoomBodyBuilder @Inject constructor( val invite3pids = params.invite3pids .takeIf { it.isNotEmpty() } ?.let { invites -> - // This can throw Exception if Identity server is not configured + // This can throw an exception if identity server is not configured ensureIdentityTokenTask.execute(Unit) val identityServerUrlWithoutProtocol = identityStore.getIdentityServerUrlWithoutProtocol() @@ -81,13 +81,14 @@ internal class CreateRoomBodyBuilder @Inject constructor( params.historyVisibility = params.historyVisibility ?: RoomHistoryVisibility.SHARED params.guestAccess = params.guestAccess ?: GuestAccess.Forbidden } - val initialStates = listOfNotNull( + val initialStates = (listOfNotNull( buildEncryptionWithAlgorithmEvent(params), buildHistoryVisibilityEvent(params), buildAvatarEvent(params), buildGuestAccess(params), buildJoinRulesRestricted(params) ) + + buildCustomInitialStates(params)) .takeIf { it.isNotEmpty() } return CreateRoomBody( @@ -95,7 +96,7 @@ internal class CreateRoomBodyBuilder @Inject constructor( roomAliasName = params.roomAliasName, name = params.name, topic = params.topic, - invitedUserIds = params.invitedUserIds.filter { it != userId }, + invitedUserIds = params.invitedUserIds.filter { it != userId }.takeIf { it.isNotEmpty() }, invite3pids = invite3pids, creationContent = params.creationContent.takeIf { it.isNotEmpty() }, initialStates = initialStates, @@ -103,10 +104,19 @@ internal class CreateRoomBodyBuilder @Inject constructor( isDirect = params.isDirect, powerLevelContentOverride = params.powerLevelContentOverride, roomVersion = params.roomVersion - ) } + private fun buildCustomInitialStates(params: CreateRoomParams): List { + return params.initialStates.map { + Event( + type = it.type, + stateKey = it.stateKey, + content = it.content + ) + } + } + private suspend fun buildAvatarEvent(params: CreateRoomParams): Event? { return params.avatarUri?.let { avatarUri -> // First upload the image, ignoring any error diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/DefaultSendService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/DefaultSendService.kt index 449189e6b5..092fec4d72 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/DefaultSendService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/DefaultSendService.kt @@ -142,7 +142,7 @@ internal class DefaultSendService @AssistedInject constructor( // The image has not yet been sent val attachmentData = ContentAttachmentData( size = messageContent.info!!.size, - mimeType = messageContent.info.mimeType!!, + mimeType = messageContent.mimeType, width = messageContent.info.width.toLong(), height = messageContent.info.height.toLong(), name = messageContent.body, @@ -169,7 +169,7 @@ internal class DefaultSendService @AssistedInject constructor( is MessageFileContent -> { val attachmentData = ContentAttachmentData( size = messageContent.info!!.size, - mimeType = messageContent.info.mimeType!!, + mimeType = messageContent.mimeType, name = messageContent.getFileName(), queryUri = Uri.parse(messageContent.url), type = ContentAttachmentData.Type.FILE @@ -181,7 +181,7 @@ internal class DefaultSendService @AssistedInject constructor( val attachmentData = ContentAttachmentData( size = messageContent.audioInfo?.size ?: 0, duration = messageContent.audioInfo?.duration?.toLong() ?: 0L, - mimeType = messageContent.audioInfo?.mimeType, + mimeType = messageContent.mimeType, name = messageContent.body, queryUri = Uri.parse(messageContent.url), type = ContentAttachmentData.Type.AUDIO diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessorCoroutine.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessorCoroutine.kt index 80bfd02b0e..3be01762e7 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessorCoroutine.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessorCoroutine.kt @@ -46,7 +46,7 @@ private const val MAX_RETRY_COUNT = 3 /** * This class is responsible for sending events in order in each room. It uses the QueuedTask.queueIdentifier to execute tasks sequentially. - * Each send is retried 3 times, if there is no network (e.g if cannot ping home server) it will wait and + * Each send is retried 3 times, if there is no network (e.g if cannot ping homeserver) it will wait and * periodically test reachability before resume (does not count as a retry) * * If the app is killed before all event were sent, on next wakeup the scheduled events will be re posted diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessorThread.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessorThread.kt index 9db7cc9039..f32890f3fb 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessorThread.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessorThread.kt @@ -42,7 +42,7 @@ import kotlin.concurrent.schedule /** * A simple ever running thread unique for that session responsible of sending events in order. - * Each send is retried 3 times, if there is no network (e.g if cannot ping home server) it will wait and + * Each send is retried 3 times, if there is no network (e.g if cannot ping homeserver) it will wait and * periodically test reachability before resume (does not count as a retry) * * If the app is killed before all event were sent, on next wakeup the scheduled events will be re posted diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/HomeServerAvailabilityChecker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/HomeServerAvailabilityChecker.kt index 2d53699917..1d7ce587f9 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/HomeServerAvailabilityChecker.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/HomeServerAvailabilityChecker.kt @@ -26,8 +26,8 @@ import java.net.Socket internal class HomeServerAvailabilityChecker(val sessionParams: SessionParams) { fun check(): Boolean { - val host = sessionParams.homeServerConnectionConfig.homeServerUri.host ?: return false - val port = sessionParams.homeServerConnectionConfig.homeServerUri.port.takeIf { it != -1 } ?: 80 + val host = sessionParams.homeServerConnectionConfig.homeServerUriBase.host ?: return false + val port = sessionParams.homeServerConnectionConfig.homeServerUriBase.port.takeIf { it != -1 } ?: 80 val timeout = 30_000 try { Socket().use { socket -> diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryDataSource.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryDataSource.kt index bff1af60ca..0b8c6df806 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryDataSource.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryDataSource.kt @@ -247,10 +247,10 @@ internal class RoomSummaryDataSource @Inject constructor(@SessionDatabase privat queryParams.roomCategoryFilter?.let { when (it) { - RoomCategoryFilter.ONLY_DM -> query.equalTo(RoomSummaryEntityFields.IS_DIRECT, true) - RoomCategoryFilter.ONLY_ROOMS -> query.equalTo(RoomSummaryEntityFields.IS_DIRECT, false) + RoomCategoryFilter.ONLY_DM -> query.equalTo(RoomSummaryEntityFields.IS_DIRECT, true) + RoomCategoryFilter.ONLY_ROOMS -> query.equalTo(RoomSummaryEntityFields.IS_DIRECT, false) RoomCategoryFilter.ONLY_WITH_NOTIFICATIONS -> query.greaterThan(RoomSummaryEntityFields.NOTIFICATION_COUNT, 0) - RoomCategoryFilter.ALL -> { + RoomCategoryFilter.ALL -> { // nop } } @@ -274,15 +274,15 @@ internal class RoomSummaryDataSource @Inject constructor(@SessionDatabase privat query.equalTo(RoomSummaryEntityFields.ROOM_TYPE, it) } when (queryParams.roomCategoryFilter) { - RoomCategoryFilter.ONLY_DM -> query.equalTo(RoomSummaryEntityFields.IS_DIRECT, true) - RoomCategoryFilter.ONLY_ROOMS -> query.equalTo(RoomSummaryEntityFields.IS_DIRECT, false) + RoomCategoryFilter.ONLY_DM -> query.equalTo(RoomSummaryEntityFields.IS_DIRECT, true) + RoomCategoryFilter.ONLY_ROOMS -> query.equalTo(RoomSummaryEntityFields.IS_DIRECT, false) RoomCategoryFilter.ONLY_WITH_NOTIFICATIONS -> query.greaterThan(RoomSummaryEntityFields.NOTIFICATION_COUNT, 0) - RoomCategoryFilter.ALL -> Unit // nop + RoomCategoryFilter.ALL -> Unit // nop } // Timber.w("VAL: activeSpaceId : ${queryParams.activeSpaceId}") when (queryParams.activeSpaceFilter) { - is ActiveSpaceFilter.ActiveSpace -> { + is ActiveSpaceFilter.ActiveSpace -> { // It's annoying but for now realm java does not support querying in primitive list :/ // https://github.com/realm/realm-java/issues/5361 if (queryParams.activeSpaceFilter.currentSpaceId == null) { @@ -300,8 +300,8 @@ internal class RoomSummaryDataSource @Inject constructor(@SessionDatabase privat } } - if (queryParams.activeGroupId != null) { - query.contains(RoomSummaryEntityFields.GROUP_IDS, queryParams.activeGroupId!!) + queryParams.activeGroupId?.let { activeGroupId -> + query.contains(RoomSummaryEntityFields.GROUP_IDS, activeGroupId) } return query } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt index 77b69991cf..9d1c0e26a3 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt @@ -187,7 +187,6 @@ internal class RoomSummaryUpdater @Inject constructor( measureTimeMillis { val lookupMap = realm.where(RoomSummaryEntity::class.java) .process(RoomSummaryEntityFields.MEMBERSHIP_STR, Membership.activeMemberships()) - .equalTo(RoomSummaryEntityFields.IS_DIRECT, false) // we order by roomID to be consistent when breaking parent/child cycles .sort(RoomSummaryEntityFields.ROOM_ID) .findAll().map { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/version/DefaultRoomVersionService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/version/DefaultRoomVersionService.kt new file mode 100644 index 0000000000..dc12c3209b --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/version/DefaultRoomVersionService.kt @@ -0,0 +1,84 @@ +/* + * Copyright 2021 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.session.room.version + +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +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.homeserver.RoomVersionStatus +import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent +import org.matrix.android.sdk.api.session.room.model.create.RoomCreateContent +import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper +import org.matrix.android.sdk.api.session.room.version.RoomVersionService +import org.matrix.android.sdk.internal.session.homeserver.HomeServerCapabilitiesDataSource +import org.matrix.android.sdk.internal.session.room.state.StateEventDataSource + +internal class DefaultRoomVersionService @AssistedInject constructor( + @Assisted private val roomId: String, + private val homeServerCapabilitiesDataSource: HomeServerCapabilitiesDataSource, + private val stateEventDataSource: StateEventDataSource, + private val roomVersionUpgradeTask: RoomVersionUpgradeTask +) : RoomVersionService { + + @AssistedFactory + interface Factory { + fun create(roomId: String): DefaultRoomVersionService + } + + override fun getRoomVersion(): String { + return stateEventDataSource.getStateEvent(roomId, EventType.STATE_ROOM_CREATE, QueryStringValue.IsEmpty) + ?.content + ?.toModel() + ?.roomVersion + // as per spec -> Defaults to "1" if the key does not exist. + ?: DEFAULT_ROOM_VERSION + } + + override suspend fun upgradeToVersion(version: String): String { + return roomVersionUpgradeTask.execute( + RoomVersionUpgradeTask.Params( + roomId = roomId, + newVersion = version + ) + ) + } + + override fun getRecommendedVersion(): String { + return homeServerCapabilitiesDataSource.getHomeServerCapabilities()?.roomVersions?.defaultRoomVersion ?: DEFAULT_ROOM_VERSION + } + + override fun isUsingUnstableRoomVersion(): Boolean { + val versionCaps = homeServerCapabilitiesDataSource.getHomeServerCapabilities()?.roomVersions + val currentVersion = getRoomVersion() + return versionCaps?.supportedVersion?.firstOrNull { it.version == currentVersion }?.status == RoomVersionStatus.UNSTABLE + } + + override fun userMayUpgradeRoom(userId: String): Boolean { + val powerLevelsHelper = stateEventDataSource.getStateEvent(roomId, EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.NoCondition) + ?.content?.toModel() + ?.let { PowerLevelsHelper(it) } + + return powerLevelsHelper?.isUserAllowedToSend(userId, true, EventType.STATE_ROOM_TOMBSTONE) ?: false + } + + companion object { + const val DEFAULT_ROOM_VERSION = "1" + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/version/RoomVersionUpgradeTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/version/RoomVersionUpgradeTask.kt new file mode 100644 index 0000000000..457bb3e948 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/version/RoomVersionUpgradeTask.kt @@ -0,0 +1,66 @@ +/* + * Copyright 2021 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.session.room.version + +import io.realm.RealmConfiguration +import org.matrix.android.sdk.api.extensions.tryOrNull +import org.matrix.android.sdk.api.session.room.model.Membership +import org.matrix.android.sdk.internal.database.awaitNotEmptyResult +import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity +import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields +import org.matrix.android.sdk.internal.di.SessionDatabase +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver +import org.matrix.android.sdk.internal.network.executeRequest +import org.matrix.android.sdk.internal.session.room.RoomAPI +import org.matrix.android.sdk.internal.session.room.RoomUpgradeBody +import org.matrix.android.sdk.internal.task.Task +import java.util.concurrent.TimeUnit +import javax.inject.Inject + +internal interface RoomVersionUpgradeTask : Task { + data class Params( + val roomId: String, + val newVersion: String + ) +} + +internal class DefaultRoomVersionUpgradeTask @Inject constructor( + private val roomAPI: RoomAPI, + private val globalErrorReceiver: GlobalErrorReceiver, + @SessionDatabase + private val realmConfiguration: RealmConfiguration +) : RoomVersionUpgradeTask { + + override suspend fun execute(params: RoomVersionUpgradeTask.Params): String { + val replacementRoomId = executeRequest(globalErrorReceiver) { + roomAPI.upgradeRoom( + roomId = params.roomId, + body = RoomUpgradeBody(params.newVersion) + ) + }.replacementRoomId + + // Wait for room to come back from the sync (but it can maybe be in the DB if the sync response is received before) + tryOrNull { + awaitNotEmptyResult(realmConfiguration, TimeUnit.MINUTES.toMillis(1L)) { realm -> + realm.where(RoomSummaryEntity::class.java) + .equalTo(RoomSummaryEntityFields.ROOM_ID, replacementRoomId) + .equalTo(RoomSummaryEntityFields.MEMBERSHIP_STR, Membership.JOIN.name) + } + } + return replacementRoomId + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpace.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpace.kt index 70c52bf4ae..233eef45f8 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpace.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpace.kt @@ -86,6 +86,12 @@ internal class DefaultSpace( ) } + override fun getChildInfo(roomId: String): SpaceChildContent? { + return room.getStateEvents(setOf(EventType.STATE_SPACE_CHILD), QueryStringValue.Equals(roomId)) + .firstOrNull() + ?.content.toModel() + } + override suspend fun setChildrenOrder(roomId: String, order: String?) { val existing = room.getStateEvents(setOf(EventType.STATE_SPACE_CHILD), QueryStringValue.Equals(roomId)) .firstOrNull() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncTask.kt index 83a2ffc446..c80fbe60c1 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncTask.kt @@ -94,7 +94,7 @@ internal class DefaultSyncTask @Inject constructor( userStore.createOrUpdate(userId) initialSyncProgressService.startRoot(InitSyncStep.ImportingAccount, 100) } - // Maybe refresh the home server capabilities data we know + // Maybe refresh the homeserver capabilities data we know getHomeServerCapabilitiesTask.execute(GetHomeServerCapabilitiesTask.Params(forceRefresh = false)) val readTimeOut = (params.timeout + TIMEOUT_MARGIN).coerceAtLeast(TimeOutInterceptor.DEFAULT_LONG_TIMEOUT) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/file/AtomicFileCreator.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/file/AtomicFileCreator.kt new file mode 100644 index 0000000000..ca10c0ed0f --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/file/AtomicFileCreator.kt @@ -0,0 +1,42 @@ +/* + * 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.util.file + +import timber.log.Timber +import java.io.File + +internal class AtomicFileCreator(private val file: File) { + val partFile = File(file.parentFile, "${file.name}.part") + + init { + if (file.exists()) { + Timber.w("## AtomicFileCreator: target file ${file.path} exists, it should not happen.") + } + if (partFile.exists()) { + Timber.d("## AtomicFileCreator: discard aborted part file ${partFile.path}") + // No need to delete the file, we will overwrite it + } + } + + fun cancel() { + partFile.delete() + } + + fun commit() { + partFile.renameTo(file) + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/wellknown/GetWellknownTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/wellknown/GetWellknownTask.kt index 7a9beac8c0..f11e87e1e7 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/wellknown/GetWellknownTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/wellknown/GetWellknownTask.kt @@ -18,7 +18,6 @@ package org.matrix.android.sdk.internal.wellknown import android.util.MalformedJsonException import dagger.Lazy -import org.matrix.android.sdk.api.MatrixPatterns import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig import org.matrix.android.sdk.api.auth.data.WellKnown import org.matrix.android.sdk.api.auth.wellknown.WellknownResult @@ -39,7 +38,11 @@ import javax.net.ssl.HttpsURLConnection internal interface GetWellknownTask : Task { data class Params( - val matrixId: String, + /** + * domain, for instance "matrix.org" + * the URL will be https://{domain}/.well-known/matrix/client + */ + val domain: String, val homeServerConnectionConfig: HomeServerConnectionConfig? ) } @@ -54,14 +57,8 @@ internal class DefaultGetWellknownTask @Inject constructor( ) : GetWellknownTask { override suspend fun execute(params: GetWellknownTask.Params): WellknownResult { - if (!MatrixPatterns.isUserId(params.matrixId)) { - return WellknownResult.InvalidMatrixId - } - - val homeServerDomain = params.matrixId.substringAfter(":") - val client = buildClient(params.homeServerConnectionConfig) - return findClientConfig(homeServerDomain, client) + return findClientConfig(params.domain, client) } private fun buildClient(homeServerConnectionConfig: HomeServerConnectionConfig?): OkHttpClient { @@ -133,7 +130,7 @@ internal class DefaultGetWellknownTask @Inject constructor( } /** - * Return true if home server is valid, and (if applicable) if identity server is pingable + * Return true if homeserver is valid, and (if applicable) if identity server is pingable */ private suspend fun validateHomeServer(homeServerBaseUrl: String, wellKnown: WellKnown, client: OkHttpClient): WellknownResult { val capabilitiesAPI = retrofitFactory.create(client, homeServerBaseUrl) @@ -189,7 +186,7 @@ internal class DefaultGetWellknownTask @Inject constructor( } /** - * Try to get an identity server URL from a home server URL, using a .wellknown request + * Try to get an identity server URL from a homeserver URL, using a .wellknown request */ /* fun getIdentityServer(homeServerUrl: String, callback: ApiCallback) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/androidsdk/crypto/data/MXDeviceInfo.java b/matrix-sdk-android/src/main/java/org/matrix/androidsdk/crypto/data/MXDeviceInfo.java index 393c633c6a..1014ceda0e 100755 --- a/matrix-sdk-android/src/main/java/org/matrix/androidsdk/crypto/data/MXDeviceInfo.java +++ b/matrix-sdk-android/src/main/java/org/matrix/androidsdk/crypto/data/MXDeviceInfo.java @@ -66,7 +66,7 @@ public class MXDeviceInfo implements Serializable { public Map> signatures; /* - * Additional data from the home server. + * Additional data from the homeserver. */ public Map unsigned; @@ -81,4 +81,4 @@ public class MXDeviceInfo implements Serializable { public MXDeviceInfo() { mVerified = DEVICE_VERIFICATION_UNKNOWN; } -} \ No newline at end of file +} diff --git a/multipicker/build.gradle b/multipicker/build.gradle index a993c452b0..04ce8a2aec 100644 --- a/multipicker/build.gradle +++ b/multipicker/build.gradle @@ -42,8 +42,8 @@ android { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation 'androidx.appcompat:appcompat:1.3.0' - implementation "androidx.fragment:fragment-ktx:1.3.5" + implementation 'androidx.appcompat:appcompat:1.3.1' + implementation "androidx.fragment:fragment-ktx:1.3.6" implementation 'androidx.exifinterface:exifinterface:1.3.2' // Log diff --git a/tools/check/forbidden_strings_in_code.txt b/tools/check/forbidden_strings_in_code.txt index e0645e00b3..ba9dec0877 100644 --- a/tools/check/forbidden_strings_in_code.txt +++ b/tools/check/forbidden_strings_in_code.txt @@ -162,7 +162,7 @@ Formatter\.formatShortFileSize===1 # android\.text\.TextUtils ### This is not a rule, but a warning: the number of "enum class" has changed. For Json classes, it is mandatory that they have `@JsonClass(generateAdapter = false)`. If the enum is not used as a Json class, change the value in file forbidden_strings_in_code.txt -enum class===101 +enum class===102 ### Do not import temporary legacy classes import org.matrix.android.sdk.internal.legacy.riot===3 diff --git a/vector/build.gradle b/vector/build.gradle index 6854c3312f..7ef5b93b8c 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -14,7 +14,7 @@ kapt { // Note: 2 digits max for each value ext.versionMajor = 1 ext.versionMinor = 1 -ext.versionPatch = 12 +ext.versionPatch = 15 static def getGitTimestamp() { def cmd = 'git show -s --format=%ct' @@ -246,6 +246,11 @@ android { productFlavors { gplay { + apply plugin: 'com.google.gms.google-services' + afterEvaluate { + tasks.matching { it.name.contains("GoogleServices") && !it.name.contains("Gplay") }*.enabled = false + } + dimension "store" isDefault = true versionName "${versionMajor}.${versionMinor}.${versionPatch}${getGplayVersionSuffix()}" @@ -300,13 +305,13 @@ android { dependencies { def epoxy_version = '4.6.2' - def fragment_version = '1.3.5' + def fragment_version = '1.3.6' def arrow_version = "0.8.2" def markwon_version = '4.1.2' def big_image_viewer_version = '1.8.0' def glide_version = '4.12.0' def moshi_version = '1.12.0' - def daggerVersion = '2.37' + def daggerVersion = '2.38' def autofill_version = "1.1.0" def work_version = '2.5.0' def arch_version = '2.1.0' @@ -315,9 +320,9 @@ dependencies { def jjwt_version = '0.11.2' // Tests - def kluent_version = '1.67' - def androidxTest_version = '1.3.0' - def espresso_version = '3.3.0' + def kluent_version = '1.68' + def androidxTest_version = '1.4.0' + def espresso_version = '3.4.0' implementation project(":matrix-sdk-android") implementation project(":matrix-sdk-android-rx") @@ -332,12 +337,12 @@ dependencies { implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version" implementation "androidx.recyclerview:recyclerview:1.2.1" - implementation 'androidx.appcompat:appcompat:1.3.0' + implementation 'androidx.appcompat:appcompat:1.3.1' implementation "androidx.fragment:fragment-ktx:$fragment_version" implementation 'androidx.constraintlayout:constraintlayout:2.0.4' implementation "androidx.sharetarget:sharetarget:1.1.0" - implementation 'androidx.core:core-ktx:1.5.0' - implementation "androidx.media:media:1.3.1" + implementation 'androidx.core:core-ktx:1.6.0' + implementation "androidx.media:media:1.4.0" implementation "androidx.transition:transition:1.4.1" implementation "org.threeten:threetenbp:1.4.0:no-tzdb" @@ -355,7 +360,7 @@ dependencies { implementation 'com.facebook.stetho:stetho:1.6.0' // Phone number https://github.com/google/libphonenumber - implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.26' + implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.28' // rx implementation 'io.reactivex.rxjava2:rxkotlin:2.4.0' @@ -386,7 +391,7 @@ dependencies { // UI implementation 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1' - implementation 'com.google.android.material:material:1.3.0' + implementation 'com.google.android.material:material:1.4.0' implementation 'me.gujun.android:span:1.7' implementation "io.noties.markwon:core:$markwon_version" implementation "io.noties.markwon:html:$markwon_version" @@ -493,7 +498,7 @@ dependencies { androidTestImplementation "androidx.test:core:$androidxTest_version" androidTestImplementation "androidx.test:runner:$androidxTest_version" androidTestImplementation "androidx.test:rules:$androidxTest_version" - androidTestImplementation 'androidx.test.ext:junit:1.1.2' + androidTestImplementation 'androidx.test.ext:junit:1.1.3' androidTestImplementation "androidx.test.espresso:espresso-core:$espresso_version" androidTestImplementation "androidx.test.espresso:espresso-contrib:$espresso_version" androidTestImplementation "androidx.test.espresso:espresso-intents:$espresso_version" @@ -506,7 +511,3 @@ dependencies { exclude group: 'org.jetbrains.kotlin' } } - -if (getGradle().getStartParameter().getTaskRequests().toString().contains("Gplay")) { - apply plugin: 'com.google.gms.google-services' -} diff --git a/vector/src/androidTest/java/im/vector/app/RegistrationTest.kt b/vector/src/androidTest/java/im/vector/app/RegistrationTest.kt index 73ca94b148..fcec2a9fb5 100644 --- a/vector/src/androidTest/java/im/vector/app/RegistrationTest.kt +++ b/vector/src/androidTest/java/im/vector/app/RegistrationTest.kt @@ -57,7 +57,7 @@ class RegistrationTest { onView(withId(R.id.loginSplashSubmit)) .perform(click()) - // Check that home server options are shown + // Check that homeserver options are shown onView(withId(R.id.loginServerTitle)) .check(matches(isDisplayed())) .check(matches(withText(R.string.login_server_title))) diff --git a/vector/src/androidTest/java/im/vector/app/ui/UiAllScreensSanityTest.kt b/vector/src/androidTest/java/im/vector/app/ui/UiAllScreensSanityTest.kt index 53e1645f09..26365e0c72 100644 --- a/vector/src/androidTest/java/im/vector/app/ui/UiAllScreensSanityTest.kt +++ b/vector/src/androidTest/java/im/vector/app/ui/UiAllScreensSanityTest.kt @@ -486,7 +486,7 @@ class UiAllScreensSanityTest { clickOn(R.string.add_identity_server) pressBack() pressBack() - // Home server + // Homeserver clickOnPreference(R.string.settings_home_server) pressBack() // Identity server diff --git a/vector/src/debug/AndroidManifest.xml b/vector/src/debug/AndroidManifest.xml index b97384099f..8ffcec6bc1 100644 --- a/vector/src/debug/AndroidManifest.xml +++ b/vector/src/debug/AndroidManifest.xml @@ -4,6 +4,7 @@ + diff --git a/vector/src/debug/java/im/vector/app/features/debug/DebugMenuActivity.kt b/vector/src/debug/java/im/vector/app/features/debug/DebugMenuActivity.kt index 539091c7ce..4b5228d199 100644 --- a/vector/src/debug/java/im/vector/app/features/debug/DebugMenuActivity.kt +++ b/vector/src/debug/java/im/vector/app/features/debug/DebugMenuActivity.kt @@ -30,9 +30,8 @@ import im.vector.app.core.di.ScreenComponent import im.vector.app.core.extensions.registerStartForActivityResult import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO -import im.vector.app.core.utils.PERMISSION_REQUEST_CODE_LAUNCH_CAMERA -import im.vector.app.core.utils.allGranted import im.vector.app.core.utils.checkPermissions +import im.vector.app.core.utils.registerForPermissionsResult import im.vector.app.core.utils.toast import im.vector.app.databinding.ActivityDebugMenuBinding import im.vector.app.features.debug.sas.DebugSasEmojiActivity @@ -48,7 +47,6 @@ import im.vector.lib.ui.styles.debug.DebugVectorButtonStylesLightActivity import im.vector.lib.ui.styles.debug.DebugVectorTextViewDarkActivity import im.vector.lib.ui.styles.debug.DebugVectorTextViewLightActivity import org.matrix.android.sdk.internal.crypto.verification.qrcode.toQrCodeData - import timber.log.Timber import javax.inject.Inject @@ -115,6 +113,9 @@ class DebugMenuActivity : VectorBaseActivity() { } views.debugTestCrash.setOnClickListener { testCrash() } views.debugScanQrCode.setOnClickListener { scanQRCode() } + views.debugPermission.setOnClickListener { + startActivity(Intent(this, DebugPermissionActivity::class.java)) + } } private fun renderQrCode(text: String) { @@ -217,15 +218,13 @@ class DebugMenuActivity : VectorBaseActivity() { } private fun scanQRCode() { - if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, this, PERMISSION_REQUEST_CODE_LAUNCH_CAMERA)) { + if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, this, permissionCameraLauncher)) { doScanQRCode() } } - override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { - super.onRequestPermissionsResult(requestCode, permissions, grantResults) - - if (requestCode == PERMISSION_REQUEST_CODE_LAUNCH_CAMERA && allGranted(grantResults)) { + private val permissionCameraLauncher = registerForPermissionsResult { allGranted, _ -> + if (allGranted) { doScanQRCode() } } diff --git a/vector/src/debug/java/im/vector/app/features/debug/DebugPermissionActivity.kt b/vector/src/debug/java/im/vector/app/features/debug/DebugPermissionActivity.kt new file mode 100644 index 0000000000..048c64bc3a --- /dev/null +++ b/vector/src/debug/java/im/vector/app/features/debug/DebugPermissionActivity.kt @@ -0,0 +1,135 @@ +/* + * Copyright 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 + +import android.Manifest +import android.content.pm.PackageManager +import android.os.Build +import android.widget.Toast +import androidx.core.app.ActivityCompat +import androidx.core.content.ContextCompat +import im.vector.app.R +import im.vector.app.core.platform.VectorBaseActivity +import im.vector.app.core.utils.checkPermissions +import im.vector.app.core.utils.onPermissionDeniedDialog +import im.vector.app.core.utils.onPermissionDeniedSnackbar +import im.vector.app.core.utils.registerForPermissionsResult +import im.vector.app.databinding.ActivityDebugPermissionBinding +import timber.log.Timber + +class DebugPermissionActivity : VectorBaseActivity() { + + override fun getBinding() = ActivityDebugPermissionBinding.inflate(layoutInflater) + + override fun getCoordinatorLayout() = views.coordinatorLayout + + // For debug + private val allPermissions = listOf( + Manifest.permission.CAMERA, + Manifest.permission.RECORD_AUDIO, + Manifest.permission.WRITE_EXTERNAL_STORAGE, + Manifest.permission.READ_EXTERNAL_STORAGE, + Manifest.permission.READ_CONTACTS) + + private var lastPermissions = emptyList() + + override fun initUiAndData() { + views.status.setOnClickListener { refresh() } + + views.camera.setOnClickListener { + lastPermissions = listOf(Manifest.permission.CAMERA) + checkPerm() + } + views.audio.setOnClickListener { + lastPermissions = listOf(Manifest.permission.RECORD_AUDIO) + checkPerm() + } + views.cameraAudio.setOnClickListener { + lastPermissions = listOf(Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO) + checkPerm() + } + views.write.setOnClickListener { + lastPermissions = listOf(Manifest.permission.WRITE_EXTERNAL_STORAGE) + checkPerm() + } + views.read.setOnClickListener { + lastPermissions = listOf(Manifest.permission.READ_EXTERNAL_STORAGE) + checkPerm() + } + views.contact.setOnClickListener { + lastPermissions = listOf(Manifest.permission.READ_CONTACTS) + checkPerm() + } + } + + private fun checkPerm() { + if (checkPermissions(lastPermissions, this, launcher, R.string.debug_rationale)) { + Toast.makeText(this, "Already granted, sync call", Toast.LENGTH_SHORT).show() + } + } + + private var dialogOrSnackbar = false + + private val launcher = registerForPermissionsResult { allGranted, deniedPermanently -> + if (allGranted) { + Toast.makeText(this, "All granted", Toast.LENGTH_SHORT).show() + } else { + if (deniedPermanently) { + dialogOrSnackbar = !dialogOrSnackbar + if (dialogOrSnackbar) { + onPermissionDeniedDialog(R.string.denied_permission_generic) + } else { + onPermissionDeniedSnackbar(R.string.denied_permission_generic) + } + } else { + Toast.makeText(this, "Denied", Toast.LENGTH_SHORT).show() + } + } + } + + override fun onResume() { + super.onResume() + refresh() + } + + private fun refresh() { + views.status.text = getStatus() + } + + private fun getStatus(): String { + return buildString { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + Timber.v("## debugPermission() : log the permissions status used by the app") + allPermissions.forEach { permission -> + append("[$permission] : ") + if (ContextCompat.checkSelfPermission(this@DebugPermissionActivity, permission) == PackageManager.PERMISSION_GRANTED) { + append("PERMISSION_GRANTED") + } else { + append("PERMISSION_DENIED") + } + append(" show rational: ") + append(ActivityCompat.shouldShowRequestPermissionRationale(this@DebugPermissionActivity, permission)) + append("\n") + } + } else { + append("Before M!") + } + append("\n") + append("(Click to refresh)") + } + } +} diff --git a/vector/src/debug/res/layout/activity_debug_menu.xml b/vector/src/debug/res/layout/activity_debug_menu.xml index a83f61266a..fadffecf83 100644 --- a/vector/src/debug/res/layout/activity_debug_menu.xml +++ b/vector/src/debug/res/layout/activity_debug_menu.xml @@ -152,6 +152,12 @@ android:layout_height="200dp" tools:src="@drawable/ic_qr_code_add" /> +