mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2025-03-18 20:29:10 +03:00
merge in static push definitions and adapt push v2 ui/logic
This commit is contained in:
commit
7091de9942
161 changed files with 1591 additions and 839 deletions
8
.github/ISSUE_TEMPLATE/release.md
vendored
8
.github/ISSUE_TEMPLATE/release.md
vendored
|
@ -7,24 +7,24 @@ assignees: bmarty
|
|||
|
||||
---
|
||||
|
||||
For the example, we are releasing the version 1.1.10
|
||||
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 the script `./tools/release/pushPlayStoreMetaData.sh`. You can check in the GooglePlay console the Activity log to check the effect.
|
||||
- [ ] 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. For instance https://github.com/matrix-org/element-android-rageshakes/labels/1.1.10-dev
|
||||
- [ ] 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` (add `--draft` for a preview)
|
||||
- [ ] 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
|
||||
|
|
49
CHANGES.md
49
CHANGES.md
|
@ -1,3 +1,52 @@
|
|||
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)
|
||||
======================================
|
||||
|
||||
|
|
68
Gemfile.lock
68
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)
|
||||
|
|
|
@ -56,7 +56,7 @@ dependencies {
|
|||
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||
implementation 'androidx.core:core-ktx:1.6.0'
|
||||
implementation 'androidx.appcompat:appcompat:1.3.0'
|
||||
implementation 'androidx.appcompat:appcompat:1.3.1'
|
||||
implementation "androidx.recyclerview:recyclerview:1.2.1"
|
||||
|
||||
implementation 'com.google.android.material:material:1.4.0'
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
Perform .well-known request first, even if the entered URL is a valid homeserver base url
|
|
@ -1 +0,0 @@
|
|||
Remove redundant mimetype (vector-im/element-web#2547)
|
|
@ -1 +0,0 @@
|
|||
Room version capabilities and room upgrade support, better error feedback
|
|
@ -1 +0,0 @@
|
|||
RawService.getWellknown() now takes a domain instead of a matrixId as parameter
|
|
@ -1 +0,0 @@
|
|||
Use different copy for self verification.
|
|
@ -1 +0,0 @@
|
|||
Crash when opening room addresses screen with no internet connection
|
|
@ -1 +0,0 @@
|
|||
Add retry support in room addresses screen
|
|
@ -1 +0,0 @@
|
|||
Fix unread messages marker being hidden in collapsed membership item
|
|
@ -1 +0,0 @@
|
|||
Ensure reaction emoji picker tabs look fine on small displays
|
|
@ -1 +0,0 @@
|
|||
Better management of permission requests
|
1
changelog.d/3681.removal
Normal file
1
changelog.d/3681.removal
Normal file
|
@ -0,0 +1 @@
|
|||
updatePushRuleActions signature has been updated to more explicitly enabled/disable the rule and update the actions. It's behaviour has also been changed to match the web with the enable/disable requests being sent on every invocation and actions sent when needed(not null).
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
2
fastlane/metadata/android/cs-CZ/changelogs/40101100.txt
Normal file
2
fastlane/metadata/android/cs-CZ/changelogs/40101100.txt
Normal file
|
@ -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
|
2
fastlane/metadata/android/cs-CZ/changelogs/40101110.txt
Normal file
2
fastlane/metadata/android/cs-CZ/changelogs/40101110.txt
Normal file
|
@ -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
|
2
fastlane/metadata/android/de-DE/changelogs/40101100.txt
Normal file
2
fastlane/metadata/android/de-DE/changelogs/40101100.txt
Normal file
|
@ -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
|
2
fastlane/metadata/android/de-DE/changelogs/40101110.txt
Normal file
2
fastlane/metadata/android/de-DE/changelogs/40101110.txt
Normal file
|
@ -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
|
2
fastlane/metadata/android/en-US/changelogs/40101130.txt
Normal file
2
fastlane/metadata/android/en-US/changelogs/40101130.txt
Normal file
|
@ -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
|
2
fastlane/metadata/android/en-US/changelogs/40101140.txt
Normal file
2
fastlane/metadata/android/en-US/changelogs/40101140.txt
Normal file
|
@ -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
|
2
fastlane/metadata/android/et/changelogs/40101100.txt
Normal file
2
fastlane/metadata/android/et/changelogs/40101100.txt
Normal file
|
@ -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
|
2
fastlane/metadata/android/et/changelogs/40101110.txt
Normal file
2
fastlane/metadata/android/et/changelogs/40101110.txt
Normal file
|
@ -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
|
2
fastlane/metadata/android/hu-HU/changelogs/40101100.txt
Normal file
2
fastlane/metadata/android/hu-HU/changelogs/40101100.txt
Normal file
|
@ -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
|
2
fastlane/metadata/android/hu-HU/changelogs/40101110.txt
Normal file
2
fastlane/metadata/android/hu-HU/changelogs/40101110.txt
Normal file
|
@ -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
|
2
fastlane/metadata/android/it-IT/changelogs/40101100.txt
Normal file
2
fastlane/metadata/android/it-IT/changelogs/40101100.txt
Normal file
|
@ -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
|
2
fastlane/metadata/android/it-IT/changelogs/40101110.txt
Normal file
2
fastlane/metadata/android/it-IT/changelogs/40101110.txt
Normal file
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
2
fastlane/metadata/android/pt-BR/changelogs/40101100.txt
Normal file
2
fastlane/metadata/android/pt-BR/changelogs/40101100.txt
Normal file
|
@ -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
|
2
fastlane/metadata/android/pt-BR/changelogs/40101110.txt
Normal file
2
fastlane/metadata/android/pt-BR/changelogs/40101110.txt
Normal file
|
@ -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
|
2
fastlane/metadata/android/uk/changelogs/40101100.txt
Normal file
2
fastlane/metadata/android/uk/changelogs/40101100.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
Основні зміни цієї версії: оновлено зовнішній вигляд та нові можливості для просторів
|
||||
Вичерпний перелік змін: https://github.com/vector-im/element-android/releases/tag/v1.1.10
|
2
fastlane/metadata/android/uk/changelogs/40101110.txt
Normal file
2
fastlane/metadata/android/uk/changelogs/40101110.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
Основні зміни цієї версії: оновлено зовнішній вигляд та нові можливості для просторів (bugfix для 1.1.10)
|
||||
Вичерпний перелік змін: https://github.com/vector-im/element-android/releases/tag/v1.1.11
|
2
fastlane/metadata/android/zh-CN/changelogs/40101100.txt
Normal file
2
fastlane/metadata/android/zh-CN/changelogs/40101100.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
此版本的主要变化:主题和样式更新以及空间的新功能。
|
||||
完整更新日志:https://github.com/vector-im/element-android/releases/tag/v1.1.10
|
2
fastlane/metadata/android/zh-CN/changelogs/40101110.txt
Normal file
2
fastlane/metadata/android/zh-CN/changelogs/40101110.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
此版本的主要变化:主题和样式更新以及空间的新功能(1.1.10 的错误修复)
|
||||
完整更新日志:https://github.com/vector-im/element-android/releases/tag/v1.1.11
|
2
fastlane/metadata/android/zh-TW/changelogs/40101100.txt
Normal file
2
fastlane/metadata/android/zh-TW/changelogs/40101100.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
此版本中的主要變動:佈景主題與樣式更新,以及空間的新功能。
|
||||
完整的變更紀錄:https://github.com/vector-im/element-android/releases/tag/v1.1.10
|
2
fastlane/metadata/android/zh-TW/changelogs/40101110.txt
Normal file
2
fastlane/metadata/android/zh-TW/changelogs/40101110.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
此版本中的主要變動:佈景主題與樣式更新,以及空間的新功能(1.1.10 的臭蟲修復版本)
|
||||
完整的變更紀錄:https://github.com/vector-im/element-android/releases/tag/v1.1.11
|
|
@ -52,7 +52,7 @@ android {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'androidx.appcompat:appcompat: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'
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -112,7 +112,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'
|
||||
|
||||
|
@ -120,7 +120,7 @@ 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.appcompat:appcompat:1.3.1"
|
||||
implementation "androidx.core:core-ktx:1.6.0"
|
||||
|
||||
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
|
||||
|
@ -169,14 +169,14 @@ dependencies {
|
|||
implementation 'com.otaliastudios:transcoder:0.10.3'
|
||||
|
||||
// Phone number https://github.com/google/libphonenumber
|
||||
implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.27'
|
||||
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.12.0'
|
||||
testImplementation 'org.amshove.kluent:kluent-android:1.67'
|
||||
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'
|
||||
|
@ -187,7 +187,7 @@ dependencies {
|
|||
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.65'
|
||||
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"
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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<KeysVersionResult?> {
|
||||
keysBackup.getCurrentVersion(it)
|
||||
}
|
||||
|
|
|
@ -17,9 +17,11 @@
|
|||
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 {
|
||||
|
||||
|
@ -27,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)
|
||||
|
||||
|
@ -173,8 +175,9 @@ object MatrixPatterns {
|
|||
* - "@bob:domain.org:3455".getDomain() will return "domain.org:3455"
|
||||
*/
|
||||
fun String.getDomain(): String {
|
||||
if (BuildConfig.DEBUG) {
|
||||
assert(isUserId(this))
|
||||
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(":")
|
||||
}
|
||||
|
|
|
@ -73,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
|
||||
}
|
||||
|
@ -138,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
|
||||
|
@ -160,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
|
||||
|
|
|
@ -38,7 +38,7 @@ data class RegistrationFlowResponse(
|
|||
val completedStages: List<String>? = 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")
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
|
@ -31,7 +31,13 @@ interface PushRuleService {
|
|||
|
||||
suspend fun addPushRule(kind: RuleKind, pushRule: PushRule)
|
||||
|
||||
suspend fun updatePushRuleActions(kind: RuleKind, oldPushRule: PushRule, newPushRule: PushRule)
|
||||
/**
|
||||
* Enables/Disables a push rule and updates the actions if necessary
|
||||
* @param enable Enables/Disables the rule
|
||||
* @param actions Actions to update if not null
|
||||
*/
|
||||
|
||||
suspend fun updatePushRuleActions(kind: RuleKind, ruleId: String, enable: Boolean, actions: List<Action>?)
|
||||
|
||||
suspend fun removePushRule(kind: RuleKind, pushRule: PushRule)
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ package org.matrix.android.sdk.api.pushrules.rest
|
|||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
import org.matrix.android.sdk.api.extensions.orFalse
|
||||
import org.matrix.android.sdk.api.pushrules.Action
|
||||
import org.matrix.android.sdk.api.pushrules.getActions
|
||||
import org.matrix.android.sdk.api.pushrules.toJson
|
||||
|
@ -100,6 +101,13 @@ data class PushRule(
|
|||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the highlight status. As spec mentions assume false if no tweak present.
|
||||
*/
|
||||
fun getHighlight(): Boolean {
|
||||
return getActions().filterIsInstance<Action.Highlight>().firstOrNull()?.highlight.orFalse()
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the notification status.
|
||||
*
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<String?>?,
|
||||
val includeType: List<String?>?,
|
||||
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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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<String, Any>()
|
||||
|
||||
/**
|
||||
* 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<CreateRoomStateEvent>()
|
||||
|
||||
/**
|
||||
* Set to true to disable federation of this room.
|
||||
* Default: false
|
||||
|
|
|
@ -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 = ""
|
||||
)
|
|
@ -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 {
|
||||
|
|
|
@ -314,6 +314,12 @@ internal class DefaultCryptoService @Inject constructor(
|
|||
cryptoCoroutineScope.launchToCallback(coroutineDispatchers.crypto, NoOpMatrixCallback()) {
|
||||
// Open the store
|
||||
cryptoStore.open()
|
||||
|
||||
if (!cryptoStore.areDeviceKeysUploaded()) {
|
||||
// Schedule upload of OTK
|
||||
oneTimeKeysUploader.updateOneTimeKeyCount(0)
|
||||
}
|
||||
|
||||
// this can throw if no network
|
||||
tryOrNull {
|
||||
uploadDeviceKeys()
|
||||
|
@ -905,7 +911,7 @@ internal class DefaultCryptoService @Inject constructor(
|
|||
* Upload my user's device keys.
|
||||
*/
|
||||
private suspend fun uploadDeviceKeys() {
|
||||
if (cryptoStore.getDeviceKeysUploaded()) {
|
||||
if (cryptoStore.areDeviceKeysUploaded()) {
|
||||
Timber.d("Keys already uploaded, nothing to do")
|
||||
return
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package org.matrix.android.sdk.internal.crypto
|
||||
|
||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||
import org.matrix.android.sdk.internal.crypto.model.MXKey
|
||||
import org.matrix.android.sdk.internal.crypto.model.rest.KeysUploadResponse
|
||||
import org.matrix.android.sdk.internal.crypto.tasks.UploadKeysTask
|
||||
|
@ -77,6 +78,10 @@ internal class OneTimeKeysUploader @Inject constructor(
|
|||
// discard the oldest private keys first. This will eventually clean
|
||||
// out stale private keys that won't receive a message.
|
||||
val keyLimit = floor(maxOneTimeKeys / 2.0).toInt()
|
||||
if (oneTimeKeyCount == null) {
|
||||
// Ask the server how many otk he has
|
||||
oneTimeKeyCount = fetchOtkCount()
|
||||
}
|
||||
val oneTimeKeyCountFromSync = oneTimeKeyCount
|
||||
if (oneTimeKeyCountFromSync != null) {
|
||||
// We need to keep a pool of one time public keys on the server so that
|
||||
|
@ -90,17 +95,22 @@ internal class OneTimeKeysUploader @Inject constructor(
|
|||
// private keys clogging up our local storage.
|
||||
// So we need some kind of engineering compromise to balance all of
|
||||
// these factors.
|
||||
try {
|
||||
tryOrNull("Unable to upload OTK") {
|
||||
val uploadedKeys = uploadOTK(oneTimeKeyCountFromSync, keyLimit)
|
||||
Timber.v("## uploadKeys() : success, $uploadedKeys key(s) sent")
|
||||
} finally {
|
||||
oneTimeKeyCheckInProgress = false
|
||||
}
|
||||
} else {
|
||||
Timber.w("maybeUploadOneTimeKeys: waiting to know the number of OTK from the sync")
|
||||
oneTimeKeyCheckInProgress = false
|
||||
lastOneTimeKeyCheck = 0
|
||||
}
|
||||
oneTimeKeyCheckInProgress = false
|
||||
}
|
||||
|
||||
private suspend fun fetchOtkCount(): Int? {
|
||||
return tryOrNull("Unable to get OTK count") {
|
||||
val result = uploadKeysTask.execute(UploadKeysTask.Params(null, null))
|
||||
result.oneTimeKeyCountsForAlgorithm(MXKey.KEY_SIGNED_CURVE_25519_TYPE)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -56,7 +56,7 @@ data class MXDeviceInfo(
|
|||
val signatures: Map<String, Map<String, String>>? = null,
|
||||
|
||||
/*
|
||||
* Additional data from the home server.
|
||||
* Additional data from the homeserver.
|
||||
*/
|
||||
@Json(name = "unsigned")
|
||||
val unsigned: JsonDict? = null,
|
||||
|
|
|
@ -475,7 +475,7 @@ internal interface IMXCryptoStore {
|
|||
fun getGossipingEvents(): List<Event>
|
||||
|
||||
fun setDeviceKeysUploaded(uploaded: Boolean)
|
||||
fun getDeviceKeysUploaded(): Boolean
|
||||
fun areDeviceKeysUploaded(): Boolean
|
||||
fun tidyUpDataBase()
|
||||
fun logDbUsageInfo()
|
||||
}
|
||||
|
|
|
@ -937,7 +937,7 @@ internal class RealmCryptoStore @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
override fun getDeviceKeysUploaded(): Boolean {
|
||||
override fun areDeviceKeysUploaded(): Boolean {
|
||||
return doWithRealm(realmConfiguration) {
|
||||
it.where<CryptoMetadataEntity>().findFirst()?.deviceKeysSentToServer
|
||||
} ?: false
|
||||
|
|
|
@ -68,7 +68,7 @@ internal class VerificationTransportToDevice(
|
|||
contentMap.setObject(otherUserId, it, keyReq)
|
||||
}
|
||||
sendToDeviceTask
|
||||
.configureWith(SendToDeviceTask.Params(MessageType.MSGTYPE_VERIFICATION_REQUEST, contentMap, localId)) {
|
||||
.configureWith(SendToDeviceTask.Params(MessageType.MSGTYPE_VERIFICATION_REQUEST, contentMap)) {
|
||||
this.callback = object : MatrixCallback<Unit> {
|
||||
override fun onSuccess(data: Unit) {
|
||||
Timber.v("## verification [$tx.transactionId] send toDevice request success")
|
||||
|
@ -124,7 +124,7 @@ internal class VerificationTransportToDevice(
|
|||
contentMap.setObject(tx.otherUserId, tx.otherDeviceId, toSendToDeviceObject)
|
||||
|
||||
sendToDeviceTask
|
||||
.configureWith(SendToDeviceTask.Params(type, contentMap, tx.transactionId)) {
|
||||
.configureWith(SendToDeviceTask.Params(type, contentMap)) {
|
||||
this.callback = object : MatrixCallback<Unit> {
|
||||
override fun onSuccess(data: Unit) {
|
||||
Timber.v("## SAS verification [$tx.transactionId] toDevice type '$type' success.")
|
||||
|
@ -155,7 +155,7 @@ internal class VerificationTransportToDevice(
|
|||
val contentMap = MXUsersDevicesMap<Any>()
|
||||
contentMap.setObject(otherUserId, otherUserDeviceId, cancelMessage)
|
||||
sendToDeviceTask
|
||||
.configureWith(SendToDeviceTask.Params(EventType.KEY_VERIFICATION_DONE, contentMap, transactionId)) {
|
||||
.configureWith(SendToDeviceTask.Params(EventType.KEY_VERIFICATION_DONE, contentMap)) {
|
||||
this.callback = object : MatrixCallback<Unit> {
|
||||
override fun onSuccess(data: Unit) {
|
||||
onDone?.invoke()
|
||||
|
@ -176,7 +176,7 @@ internal class VerificationTransportToDevice(
|
|||
val contentMap = MXUsersDevicesMap<Any>()
|
||||
contentMap.setObject(otherUserId, otherUserDeviceId, cancelMessage)
|
||||
sendToDeviceTask
|
||||
.configureWith(SendToDeviceTask.Params(EventType.KEY_VERIFICATION_CANCEL, contentMap, transactionId)) {
|
||||
.configureWith(SendToDeviceTask.Params(EventType.KEY_VERIFICATION_CANCEL, contentMap)) {
|
||||
this.callback = object : MatrixCallback<Unit> {
|
||||
override fun onSuccess(data: Unit) {
|
||||
Timber.v("## SAS verification [$transactionId] canceled for reason ${code.value}")
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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<TlsVersion> 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<CipherSuite> 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;
|
||||
|
|
|
@ -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<HomeServerConnectionConfig> 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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<CallInviteContent>() ?: 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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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<CallCandidate>) {
|
||||
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(
|
||||
|
|
|
@ -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<ThreePid>): Map<ThreePid, SharedState> {
|
||||
// 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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
*
|
||||
|
|
|
@ -113,8 +113,8 @@ internal class DefaultPushRuleService @Inject constructor(
|
|||
addPushRuleTask.execute(AddPushRuleTask.Params(kind, pushRule))
|
||||
}
|
||||
|
||||
override suspend fun updatePushRuleActions(kind: RuleKind, oldPushRule: PushRule, newPushRule: PushRule) {
|
||||
updatePushRuleActionsTask.execute(UpdatePushRuleActionsTask.Params(kind, oldPushRule, newPushRule))
|
||||
override suspend fun updatePushRuleActions(kind: RuleKind, ruleId: String, enable: Boolean, actions: List<Action>?) {
|
||||
updatePushRuleActionsTask.execute(UpdatePushRuleActionsTask.Params(kind, ruleId, enable, actions))
|
||||
}
|
||||
|
||||
override suspend fun removePushRule(kind: RuleKind, pushRule: PushRule) {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -15,8 +15,9 @@
|
|||
*/
|
||||
package org.matrix.android.sdk.internal.session.pushers
|
||||
|
||||
import org.matrix.android.sdk.api.pushrules.Action
|
||||
import org.matrix.android.sdk.api.pushrules.RuleKind
|
||||
import org.matrix.android.sdk.api.pushrules.rest.PushRule
|
||||
import org.matrix.android.sdk.api.pushrules.toJson
|
||||
import org.matrix.android.sdk.internal.network.GlobalErrorReceiver
|
||||
import org.matrix.android.sdk.internal.network.executeRequest
|
||||
import org.matrix.android.sdk.internal.task.Task
|
||||
|
@ -25,8 +26,9 @@ import javax.inject.Inject
|
|||
internal interface UpdatePushRuleActionsTask : Task<UpdatePushRuleActionsTask.Params, Unit> {
|
||||
data class Params(
|
||||
val kind: RuleKind,
|
||||
val oldPushRule: PushRule,
|
||||
val newPushRule: PushRule
|
||||
val ruleId: String,
|
||||
val enable: Boolean,
|
||||
val actions: List<Action>?
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -36,20 +38,14 @@ internal class DefaultUpdatePushRuleActionsTask @Inject constructor(
|
|||
) : UpdatePushRuleActionsTask {
|
||||
|
||||
override suspend fun execute(params: UpdatePushRuleActionsTask.Params) {
|
||||
if (params.oldPushRule.enabled != params.newPushRule.enabled) {
|
||||
// First change enabled state
|
||||
executeRequest(globalErrorReceiver) {
|
||||
pushRulesApi.updateEnableRuleStatus(params.kind.value, params.newPushRule.ruleId, params.newPushRule.enabled)
|
||||
pushRulesApi.updateEnableRuleStatus(params.kind.value, params.ruleId, enable = params.enable)
|
||||
}
|
||||
}
|
||||
|
||||
if (params.newPushRule.enabled) {
|
||||
// Also ensure the actions are up to date
|
||||
val body = mapOf("actions" to params.newPushRule.actions)
|
||||
|
||||
executeRequest(globalErrorReceiver) {
|
||||
pushRulesApi.updateRuleActions(params.kind.value, params.newPushRule.ruleId, body)
|
||||
if (params.actions != null) {
|
||||
val body = mapOf("actions" to params.actions.toJson())
|
||||
executeRequest(globalErrorReceiver) {
|
||||
pushRulesApi.updateRuleActions(params.kind.value, params.ruleId, body)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Event> {
|
||||
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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -130,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)
|
||||
|
@ -186,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<String?>) {
|
||||
|
|
|
@ -66,7 +66,7 @@ public class MXDeviceInfo implements Serializable {
|
|||
public Map<String, Map<String, String>> signatures;
|
||||
|
||||
/*
|
||||
* Additional data from the home server.
|
||||
* Additional data from the homeserver.
|
||||
*/
|
||||
public Map<String, Object> unsigned;
|
||||
|
||||
|
@ -81,4 +81,4 @@ public class MXDeviceInfo implements Serializable {
|
|||
public MXDeviceInfo() {
|
||||
mVerified = DEVICE_VERIFICATION_UNKNOWN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -14,7 +14,7 @@ kapt {
|
|||
// Note: 2 digits max for each value
|
||||
ext.versionMajor = 1
|
||||
ext.versionMinor = 1
|
||||
ext.versionPatch = 13
|
||||
ext.versionPatch = 15
|
||||
|
||||
static def getGitTimestamp() {
|
||||
def cmd = 'git show -s --format=%ct'
|
||||
|
@ -309,13 +309,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'
|
||||
|
@ -324,7 +324,7 @@ dependencies {
|
|||
def jjwt_version = '0.11.2'
|
||||
|
||||
// Tests
|
||||
def kluent_version = '1.67'
|
||||
def kluent_version = '1.68'
|
||||
def androidxTest_version = '1.4.0'
|
||||
def espresso_version = '3.4.0'
|
||||
|
||||
|
@ -341,12 +341,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.6.0'
|
||||
implementation "androidx.media:media:1.3.1"
|
||||
implementation "androidx.media:media:1.4.0"
|
||||
implementation "androidx.transition:transition:1.4.1"
|
||||
|
||||
implementation "org.threeten:threetenbp:1.4.0:no-tzdb"
|
||||
|
@ -364,7 +364,7 @@ dependencies {
|
|||
implementation 'com.facebook.stetho:stetho:1.6.0'
|
||||
|
||||
// Phone number https://github.com/google/libphonenumber
|
||||
implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.27'
|
||||
implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.28'
|
||||
|
||||
// rx
|
||||
implementation 'io.reactivex.rxjava2:rxkotlin:2.4.0'
|
||||
|
|
|
@ -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)))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -111,12 +111,12 @@ import im.vector.app.features.roomprofile.settings.RoomSettingsFragment
|
|||
import im.vector.app.features.roomprofile.uploads.RoomUploadsFragment
|
||||
import im.vector.app.features.roomprofile.uploads.files.RoomUploadsFilesFragment
|
||||
import im.vector.app.features.roomprofile.uploads.media.RoomUploadsMediaFragment
|
||||
import im.vector.app.features.settings.VectorSettingsAdvancedNotificationPreferenceFragment
|
||||
import im.vector.app.features.settings.notifications.VectorSettingsAdvancedNotificationPreferenceFragment
|
||||
import im.vector.app.features.settings.VectorSettingsGeneralFragment
|
||||
import im.vector.app.features.settings.VectorSettingsHelpAboutFragment
|
||||
import im.vector.app.features.settings.VectorSettingsLabsFragment
|
||||
import im.vector.app.features.settings.VectorSettingsNotificationPreferenceFragment
|
||||
import im.vector.app.features.settings.VectorSettingsNotificationsTroubleshootFragment
|
||||
import im.vector.app.features.settings.notifications.VectorSettingsNotificationPreferenceFragment
|
||||
import im.vector.app.features.settings.notifications.VectorSettingsNotificationsTroubleshootFragment
|
||||
import im.vector.app.features.settings.VectorSettingsPinFragment
|
||||
import im.vector.app.features.settings.VectorSettingsPreferencesFragment
|
||||
import im.vector.app.features.settings.VectorSettingsSecurityPrivacyFragment
|
||||
|
|
|
@ -22,18 +22,14 @@ import android.view.View
|
|||
import android.widget.RadioGroup
|
||||
import androidx.preference.PreferenceViewHolder
|
||||
import im.vector.app.R
|
||||
import org.matrix.android.sdk.api.pushrules.Action
|
||||
import org.matrix.android.sdk.api.pushrules.RuleIds
|
||||
import org.matrix.android.sdk.api.pushrules.RuleSetKey
|
||||
import org.matrix.android.sdk.api.pushrules.rest.PushRule
|
||||
import org.matrix.android.sdk.api.pushrules.rest.PushRuleAndKind
|
||||
import im.vector.app.features.settings.notifications.NotificationIndex
|
||||
|
||||
class PushRulePreference : VectorPreference {
|
||||
|
||||
/**
|
||||
* @return the selected push rule and its kind
|
||||
* @return the selected push rule index
|
||||
*/
|
||||
var ruleAndKind: PushRuleAndKind? = null
|
||||
var index: NotificationIndex? = null
|
||||
private set
|
||||
|
||||
constructor(context: Context) : super(context)
|
||||
|
@ -47,44 +43,12 @@ class PushRulePreference : VectorPreference {
|
|||
}
|
||||
|
||||
/**
|
||||
* @return the bing rule status index
|
||||
*/
|
||||
private val ruleStatusIndex: Int
|
||||
get() {
|
||||
val safeRule = ruleAndKind?.pushRule ?: return NOTIFICATION_OFF_INDEX
|
||||
|
||||
if (safeRule.ruleId == RuleIds.RULE_ID_SUPPRESS_BOTS_NOTIFICATIONS) {
|
||||
if (safeRule.shouldNotNotify()) {
|
||||
return if (safeRule.enabled) {
|
||||
NOTIFICATION_OFF_INDEX
|
||||
} else {
|
||||
NOTIFICATION_SILENT_INDEX
|
||||
}
|
||||
} else if (safeRule.shouldNotify()) {
|
||||
return NOTIFICATION_NOISY_INDEX
|
||||
}
|
||||
}
|
||||
|
||||
if (safeRule.enabled) {
|
||||
return if (safeRule.shouldNotNotify()) {
|
||||
NOTIFICATION_OFF_INDEX
|
||||
} else if (safeRule.getNotificationSound() != null) {
|
||||
NOTIFICATION_NOISY_INDEX
|
||||
} else {
|
||||
NOTIFICATION_SILENT_INDEX
|
||||
}
|
||||
}
|
||||
|
||||
return NOTIFICATION_OFF_INDEX
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the push rule.
|
||||
* Update the notification index.
|
||||
*
|
||||
* @param pushRule
|
||||
*/
|
||||
fun setPushRule(pushRuleAndKind: PushRuleAndKind?) {
|
||||
ruleAndKind = pushRuleAndKind
|
||||
fun setIndex(notificationIndex: NotificationIndex?) {
|
||||
index = notificationIndex
|
||||
refreshSummary()
|
||||
}
|
||||
|
||||
|
@ -92,74 +56,13 @@ class PushRulePreference : VectorPreference {
|
|||
* Refresh the summary
|
||||
*/
|
||||
private fun refreshSummary() {
|
||||
summary = context.getString(when (ruleStatusIndex) {
|
||||
NOTIFICATION_OFF_INDEX -> R.string.notification_off
|
||||
NOTIFICATION_SILENT_INDEX -> R.string.notification_silent
|
||||
else -> R.string.notification_noisy
|
||||
summary = context.getString(when (index) {
|
||||
NotificationIndex.OFF -> R.string.notification_off
|
||||
NotificationIndex.SILENT -> R.string.notification_silent
|
||||
NotificationIndex.NOISY, null -> R.string.notification_noisy
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a push rule with the updated required at index.
|
||||
*
|
||||
* @param index index
|
||||
* @return a push rule with the updated flags / null if there is no update
|
||||
*/
|
||||
fun createNewRule(index: Int): PushRule? {
|
||||
val safeRule = ruleAndKind?.pushRule ?: return null
|
||||
val safeKind = ruleAndKind?.kind ?: return null
|
||||
|
||||
return if (index != ruleStatusIndex) {
|
||||
if (safeRule.ruleId == RuleIds.RULE_ID_SUPPRESS_BOTS_NOTIFICATIONS) {
|
||||
when (index) {
|
||||
NOTIFICATION_OFF_INDEX -> {
|
||||
safeRule.copy(enabled = true)
|
||||
.setNotify(false)
|
||||
.removeNotificationSound()
|
||||
}
|
||||
NOTIFICATION_SILENT_INDEX -> {
|
||||
safeRule.copy(enabled = false)
|
||||
.setNotify(false)
|
||||
}
|
||||
NOTIFICATION_NOISY_INDEX -> {
|
||||
safeRule.copy(enabled = true)
|
||||
.setNotify(true)
|
||||
.setNotificationSound()
|
||||
}
|
||||
else -> safeRule
|
||||
}
|
||||
} else {
|
||||
if (NOTIFICATION_OFF_INDEX == index) {
|
||||
if (safeKind == RuleSetKey.UNDERRIDE || safeRule.ruleId == RuleIds.RULE_ID_SUPPRESS_BOTS_NOTIFICATIONS) {
|
||||
safeRule.setNotify(false)
|
||||
} else {
|
||||
safeRule.copy(enabled = false)
|
||||
}
|
||||
} else {
|
||||
val newRule = safeRule.copy(enabled = true)
|
||||
.setNotify(true)
|
||||
.setHighlight(safeKind != RuleSetKey.UNDERRIDE
|
||||
&& safeRule.ruleId != RuleIds.RULE_ID_INVITE_ME
|
||||
&& NOTIFICATION_NOISY_INDEX == index)
|
||||
|
||||
if (NOTIFICATION_NOISY_INDEX == index) {
|
||||
newRule.setNotificationSound(
|
||||
if (safeRule.ruleId == RuleIds.RULE_ID_CALL) {
|
||||
Action.ACTION_OBJECT_VALUE_VALUE_RING
|
||||
} else {
|
||||
Action.ACTION_OBJECT_VALUE_VALUE_DEFAULT
|
||||
}
|
||||
)
|
||||
} else {
|
||||
newRule.removeNotificationSound()
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
safeRule
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: PreferenceViewHolder) {
|
||||
super.onBindViewHolder(holder)
|
||||
|
||||
|
@ -170,14 +73,14 @@ class PushRulePreference : VectorPreference {
|
|||
val radioGroup = holder.findViewById(R.id.bingPreferenceRadioGroup) as? RadioGroup
|
||||
radioGroup?.setOnCheckedChangeListener(null)
|
||||
|
||||
when (ruleStatusIndex) {
|
||||
NOTIFICATION_OFF_INDEX -> {
|
||||
when (index) {
|
||||
NotificationIndex.OFF -> {
|
||||
radioGroup?.check(R.id.bingPreferenceRadioBingRuleOff)
|
||||
}
|
||||
NOTIFICATION_SILENT_INDEX -> {
|
||||
NotificationIndex.SILENT -> {
|
||||
radioGroup?.check(R.id.bingPreferenceRadioBingRuleSilent)
|
||||
}
|
||||
else -> {
|
||||
NotificationIndex.NOISY -> {
|
||||
radioGroup?.check(R.id.bingPreferenceRadioBingRuleNoisy)
|
||||
}
|
||||
}
|
||||
|
@ -185,23 +88,15 @@ class PushRulePreference : VectorPreference {
|
|||
radioGroup?.setOnCheckedChangeListener { _, checkedId ->
|
||||
when (checkedId) {
|
||||
R.id.bingPreferenceRadioBingRuleOff -> {
|
||||
onPreferenceChangeListener?.onPreferenceChange(this, NOTIFICATION_OFF_INDEX)
|
||||
onPreferenceChangeListener?.onPreferenceChange(this, NotificationIndex.OFF)
|
||||
}
|
||||
R.id.bingPreferenceRadioBingRuleSilent -> {
|
||||
onPreferenceChangeListener?.onPreferenceChange(this, NOTIFICATION_SILENT_INDEX)
|
||||
onPreferenceChangeListener?.onPreferenceChange(this, NotificationIndex.SILENT)
|
||||
}
|
||||
R.id.bingPreferenceRadioBingRuleNoisy -> {
|
||||
onPreferenceChangeListener?.onPreferenceChange(this, NOTIFICATION_NOISY_INDEX)
|
||||
onPreferenceChangeListener?.onPreferenceChange(this, NotificationIndex.NOISY)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
// index in mRuleStatuses
|
||||
private const val NOTIFICATION_OFF_INDEX = 0
|
||||
private const val NOTIFICATION_SILENT_INDEX = 1
|
||||
private const val NOTIFICATION_NOISY_INDEX = 2
|
||||
}
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue