From 32cf3feab8d0303c8662c2fc28e85f670052e36f Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Mon, 28 Mar 2022 14:45:40 +0300 Subject: [PATCH 1/7] Create beacon content class. --- .../sdk/api/session/room/model/BeaconInfo.kt | 33 +++++++++++++++++ .../room/model/LiveLocationBeaconContent.kt | 37 +++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/BeaconInfo.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/LiveLocationBeaconContent.kt diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/BeaconInfo.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/BeaconInfo.kt new file mode 100644 index 0000000000..2f9eeacd65 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/BeaconInfo.kt @@ -0,0 +1,33 @@ +/* + * Copyright 2020 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.api.session.room.model + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +data class BeaconInfo( + @Json(name = "description") val description: String? = null, + /** + * Beacon should be considered as inactive after this timeout as milliseconds. + */ + @Json(name = "timeout") val timeout: Long? = null, + /** + * Should be set true to start sharing beacon. + */ + @Json(name = "live") val isLive: Boolean? = null +) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/LiveLocationBeaconContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/LiveLocationBeaconContent.kt new file mode 100644 index 0000000000..b21296b4aa --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/LiveLocationBeaconContent.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2020 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.api.session.room.model + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass +import org.matrix.android.sdk.api.session.room.model.message.LocationAsset + +@JsonClass(generateAdapter = true) +data class LiveLocationBeaconContent( + /** + * Indicates user's intent to share ephemeral location. + */ + @Json(name = "m.beacon_info") val beaconInfo: BeaconInfo? = null, + /** + * Beacon creation timestamp. + */ + @Json(name = "m.ts") val ts: Long? = null, + /** + * Live location asset type. + */ + @Json(name = "m.asset") val locationAsset: LocationAsset = LocationAsset(type = "m.self.live") +) From 152c92101750d7e2fd5b8ec16d8b863d9dd9372c Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Mon, 28 Mar 2022 16:23:51 +0300 Subject: [PATCH 2/7] Send beacon info. --- .../sdk/api/session/events/model/EventType.kt | 1 + .../location/LocationSharingService.kt | 33 +++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/EventType.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/EventType.kt index 22fb9bcbe2..460b9ae1d2 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/EventType.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/EventType.kt @@ -49,6 +49,7 @@ object EventType { const val STATE_ROOM_JOIN_RULES = "m.room.join_rules" const val STATE_ROOM_GUEST_ACCESS = "m.room.guest_access" const val STATE_ROOM_POWER_LEVELS = "m.room.power_levels" + const val STATE_ROOM_BEACON_INFO = "m.beacon_info" const val STATE_SPACE_CHILD = "m.space.child" diff --git a/vector/src/main/java/im/vector/app/features/location/LocationSharingService.kt b/vector/src/main/java/im/vector/app/features/location/LocationSharingService.kt index a2a68e4188..347443dc4e 100644 --- a/vector/src/main/java/im/vector/app/features/location/LocationSharingService.kt +++ b/vector/src/main/java/im/vector/app/features/location/LocationSharingService.kt @@ -22,7 +22,14 @@ import android.os.Parcelable import dagger.hilt.android.AndroidEntryPoint import im.vector.app.core.services.VectorService import im.vector.app.features.notifications.NotificationUtils +import im.vector.app.features.session.coroutineScope +import kotlinx.coroutines.launch import kotlinx.parcelize.Parcelize +import org.matrix.android.sdk.api.session.Session +import org.matrix.android.sdk.api.session.events.model.EventType +import org.matrix.android.sdk.api.session.events.model.toContent +import org.matrix.android.sdk.api.session.room.model.BeaconInfo +import org.matrix.android.sdk.api.session.room.model.LiveLocationBeaconContent import timber.log.Timber import java.util.Timer import java.util.TimerTask @@ -40,6 +47,7 @@ class LocationSharingService : VectorService(), LocationTracker.Callback { @Inject lateinit var notificationUtils: NotificationUtils @Inject lateinit var locationTracker: LocationTracker + @Inject lateinit var session: Session private var roomArgsList = mutableListOf() private var timers = mutableListOf() @@ -67,11 +75,36 @@ class LocationSharingService : VectorService(), LocationTracker.Callback { // Schedule a timer to stop sharing scheduleTimer(roomArgs.roomId, roomArgs.durationMillis) + + // Send beacon info state event + session.coroutineScope.launch { + sendBeaconInfo(roomArgs) + } } return START_STICKY } + private suspend fun sendBeaconInfo(roomArgs: RoomArgs) { + val beaconContent = LiveLocationBeaconContent( + beaconInfo = BeaconInfo( + timeout = roomArgs.durationMillis, + isLive = true + ), + ts = System.currentTimeMillis() + ).toContent() + + // This format is not yet finalized + val stateKey = session.myUserId + session + .getRoom(roomArgs.roomId) + ?.sendStateEvent( + eventType = EventType.STATE_ROOM_BEACON_INFO, + stateKey = stateKey, + body = beaconContent + ) + } + private fun scheduleTimer(roomId: String, durationMillis: Long) { Timer() .apply { From 6952552e5ebc7e46a7c8a8870c562da33ce6a749 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Mon, 28 Mar 2022 16:29:24 +0300 Subject: [PATCH 3/7] Changelog added. --- changelog.d/5651.feature | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/5651.feature diff --git a/changelog.d/5651.feature b/changelog.d/5651.feature new file mode 100644 index 0000000000..c633c01944 --- /dev/null +++ b/changelog.d/5651.feature @@ -0,0 +1 @@ +Send beacon info state event when live location sharing started \ No newline at end of file From 2a4182ea8421e6179b75acfb20133ef096b416e5 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Tue, 29 Mar 2022 11:53:44 +0300 Subject: [PATCH 4/7] Code review fixes. --- .../room/model/LiveLocationBeaconContent.kt | 2 +- .../location/LocationSharingService.kt | 19 +++++++++++++------ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/LiveLocationBeaconContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/LiveLocationBeaconContent.kt index b21296b4aa..1c80984d2d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/LiveLocationBeaconContent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/LiveLocationBeaconContent.kt @@ -29,7 +29,7 @@ data class LiveLocationBeaconContent( /** * Beacon creation timestamp. */ - @Json(name = "m.ts") val ts: Long? = null, + @Json(name = "m.ts") val timestampAsMillisecond: Long? = null, /** * Live location asset type. */ diff --git a/vector/src/main/java/im/vector/app/features/location/LocationSharingService.kt b/vector/src/main/java/im/vector/app/features/location/LocationSharingService.kt index 347443dc4e..0a330b497b 100644 --- a/vector/src/main/java/im/vector/app/features/location/LocationSharingService.kt +++ b/vector/src/main/java/im/vector/app/features/location/LocationSharingService.kt @@ -20,7 +20,9 @@ import android.content.Intent import android.os.IBinder import android.os.Parcelable import dagger.hilt.android.AndroidEntryPoint +import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.services.VectorService +import im.vector.app.core.time.Clock import im.vector.app.features.notifications.NotificationUtils import im.vector.app.features.session.coroutineScope import kotlinx.coroutines.launch @@ -47,7 +49,8 @@ class LocationSharingService : VectorService(), LocationTracker.Callback { @Inject lateinit var notificationUtils: NotificationUtils @Inject lateinit var locationTracker: LocationTracker - @Inject lateinit var session: Session + @Inject lateinit var activeSessionHolder: ActiveSessionHolder + @Inject lateinit var clock: Clock private var roomArgsList = mutableListOf() private var timers = mutableListOf() @@ -77,21 +80,25 @@ class LocationSharingService : VectorService(), LocationTracker.Callback { scheduleTimer(roomArgs.roomId, roomArgs.durationMillis) // Send beacon info state event - session.coroutineScope.launch { - sendBeaconInfo(roomArgs) - } + activeSessionHolder + .getSafeActiveSession() + ?.let { session -> + session.coroutineScope.launch { + sendBeaconInfo(session, roomArgs) + } + } } return START_STICKY } - private suspend fun sendBeaconInfo(roomArgs: RoomArgs) { + private suspend fun sendBeaconInfo(session: Session, roomArgs: RoomArgs) { val beaconContent = LiveLocationBeaconContent( beaconInfo = BeaconInfo( timeout = roomArgs.durationMillis, isLive = true ), - ts = System.currentTimeMillis() + timestampAsMillisecond = clock.epochMillis() ).toContent() // This format is not yet finalized From 922d68cfda52fc3bcfff4547c731b346480a2a9d Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Fri, 1 Apr 2022 15:01:25 +0300 Subject: [PATCH 5/7] Code review fixes, use unstable prefixes as MSCs suggest. --- .../sdk/api/session/events/model/EventType.kt | 10 +++++++++- .../room/model/LiveLocationBeaconContent.kt | 14 ++++++++++++-- .../features/location/LocationSharingService.kt | 10 +++++----- 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/EventType.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/EventType.kt index 460b9ae1d2..855801e79e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/EventType.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/EventType.kt @@ -49,7 +49,7 @@ object EventType { const val STATE_ROOM_JOIN_RULES = "m.room.join_rules" const val STATE_ROOM_GUEST_ACCESS = "m.room.guest_access" const val STATE_ROOM_POWER_LEVELS = "m.room.power_levels" - const val STATE_ROOM_BEACON_INFO = "m.beacon_info" + private const val STATE_ROOM_BEACON_INFO_PREFIX = "org.matrix.msc3489.beacon_info." const val STATE_SPACE_CHILD = "m.space.child" @@ -121,4 +121,12 @@ object EventType { type == CALL_REJECT || type == CALL_REPLACES } + + /** + * Returns an event type like org.matrix.msc3489.beacon_info.@userid:matrix.org.1648814272273 + */ + fun generateBeaconInfoStateEventType(userId: String): String { + val uniqueId = System.currentTimeMillis() + return "$STATE_ROOM_BEACON_INFO_PREFIX$userId.$uniqueId" + } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/LiveLocationBeaconContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/LiveLocationBeaconContent.kt index 1c80984d2d..d32dcc7dfd 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/LiveLocationBeaconContent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/LiveLocationBeaconContent.kt @@ -25,13 +25,23 @@ data class LiveLocationBeaconContent( /** * Indicates user's intent to share ephemeral location. */ + @Json(name = "org.matrix.msc3489.beacon_info") val unstableBeaconInfo: BeaconInfo? = null, @Json(name = "m.beacon_info") val beaconInfo: BeaconInfo? = null, /** * Beacon creation timestamp. */ + @Json(name = "org.matrix.msc3488.ts") val unstableTimestampAsMilliseconds: Long? = null, @Json(name = "m.ts") val timestampAsMillisecond: Long? = null, /** * Live location asset type. */ - @Json(name = "m.asset") val locationAsset: LocationAsset = LocationAsset(type = "m.self.live") -) + @Json(name = "org.matrix.msc3488.asset") val unstableLocationAsset: LocationAsset = LocationAsset("m.self"), + @Json(name = "m.asset") val locationAsset: LocationAsset? = null +) { + + fun getBestBeaconInfo() = beaconInfo ?: unstableBeaconInfo + + fun getBestTimestampAsMilliseconds() = timestampAsMillisecond ?: unstableTimestampAsMilliseconds + + fun getBestLocationAsset() = locationAsset ?: unstableLocationAsset +} diff --git a/vector/src/main/java/im/vector/app/features/location/LocationSharingService.kt b/vector/src/main/java/im/vector/app/features/location/LocationSharingService.kt index 0a330b497b..36a299ef25 100644 --- a/vector/src/main/java/im/vector/app/features/location/LocationSharingService.kt +++ b/vector/src/main/java/im/vector/app/features/location/LocationSharingService.kt @@ -28,7 +28,7 @@ import im.vector.app.features.session.coroutineScope import kotlinx.coroutines.launch import kotlinx.parcelize.Parcelize import org.matrix.android.sdk.api.session.Session -import org.matrix.android.sdk.api.session.events.model.EventType +import org.matrix.android.sdk.api.session.events.model.EventType.generateBeaconInfoStateEventType import org.matrix.android.sdk.api.session.events.model.toContent import org.matrix.android.sdk.api.session.room.model.BeaconInfo import org.matrix.android.sdk.api.session.room.model.LiveLocationBeaconContent @@ -94,19 +94,19 @@ class LocationSharingService : VectorService(), LocationTracker.Callback { private suspend fun sendBeaconInfo(session: Session, roomArgs: RoomArgs) { val beaconContent = LiveLocationBeaconContent( - beaconInfo = BeaconInfo( + unstableBeaconInfo = BeaconInfo( timeout = roomArgs.durationMillis, isLive = true ), - timestampAsMillisecond = clock.epochMillis() + unstableTimestampAsMilliseconds = clock.epochMillis() ).toContent() - // This format is not yet finalized + val eventType = generateBeaconInfoStateEventType(session.myUserId) val stateKey = session.myUserId session .getRoom(roomArgs.roomId) ?.sendStateEvent( - eventType = EventType.STATE_ROOM_BEACON_INFO, + eventType = eventType, stateKey = stateKey, body = beaconContent ) From 97de6de8f29febc6598140bae1c2ee921e0226d1 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Fri, 1 Apr 2022 17:04:52 +0300 Subject: [PATCH 6/7] Code review fixes. --- .../room/model/{ => livelocation}/BeaconInfo.kt | 4 ++-- .../{ => livelocation}/LiveLocationBeaconContent.kt | 11 ++++++----- .../app/features/location/LocationSharingService.kt | 6 +++--- 3 files changed, 11 insertions(+), 10 deletions(-) rename matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/{ => livelocation}/BeaconInfo.kt (90%) rename matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/{ => livelocation}/LiveLocationBeaconContent.kt (81%) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/BeaconInfo.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/livelocation/BeaconInfo.kt similarity index 90% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/BeaconInfo.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/livelocation/BeaconInfo.kt index 2f9eeacd65..873edc0f1f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/BeaconInfo.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/livelocation/BeaconInfo.kt @@ -1,5 +1,5 @@ /* - * Copyright 2020 The Matrix.org Foundation C.I.C. + * Copyright 2022 The Matrix.org Foundation C.I.C. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.matrix.android.sdk.api.session.room.model +package org.matrix.android.sdk.api.session.room.model.livelocation import com.squareup.moshi.Json import com.squareup.moshi.JsonClass diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/LiveLocationBeaconContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/livelocation/LiveLocationBeaconContent.kt similarity index 81% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/LiveLocationBeaconContent.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/livelocation/LiveLocationBeaconContent.kt index d32dcc7dfd..e07df14aee 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/LiveLocationBeaconContent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/livelocation/LiveLocationBeaconContent.kt @@ -1,5 +1,5 @@ /* - * Copyright 2020 The Matrix.org Foundation C.I.C. + * Copyright (c) 2022 New Vector Ltd * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,11 +14,12 @@ * limitations under the License. */ -package org.matrix.android.sdk.api.session.room.model +package org.matrix.android.sdk.api.session.room.model.livelocation import com.squareup.moshi.Json import com.squareup.moshi.JsonClass import org.matrix.android.sdk.api.session.room.model.message.LocationAsset +import org.matrix.android.sdk.api.session.room.model.message.LocationAssetType @JsonClass(generateAdapter = true) data class LiveLocationBeaconContent( @@ -31,17 +32,17 @@ data class LiveLocationBeaconContent( * Beacon creation timestamp. */ @Json(name = "org.matrix.msc3488.ts") val unstableTimestampAsMilliseconds: Long? = null, - @Json(name = "m.ts") val timestampAsMillisecond: Long? = null, + @Json(name = "m.ts") val timestampAsMilliseconds: Long? = null, /** * Live location asset type. */ - @Json(name = "org.matrix.msc3488.asset") val unstableLocationAsset: LocationAsset = LocationAsset("m.self"), + @Json(name = "org.matrix.msc3488.asset") val unstableLocationAsset: LocationAsset = LocationAsset(LocationAssetType.SELF), @Json(name = "m.asset") val locationAsset: LocationAsset? = null ) { fun getBestBeaconInfo() = beaconInfo ?: unstableBeaconInfo - fun getBestTimestampAsMilliseconds() = timestampAsMillisecond ?: unstableTimestampAsMilliseconds + fun getBestTimestampAsMilliseconds() = timestampAsMilliseconds ?: unstableTimestampAsMilliseconds fun getBestLocationAsset() = locationAsset ?: unstableLocationAsset } diff --git a/vector/src/main/java/im/vector/app/features/location/LocationSharingService.kt b/vector/src/main/java/im/vector/app/features/location/LocationSharingService.kt index 36a299ef25..4b4f051abf 100644 --- a/vector/src/main/java/im/vector/app/features/location/LocationSharingService.kt +++ b/vector/src/main/java/im/vector/app/features/location/LocationSharingService.kt @@ -30,8 +30,8 @@ import kotlinx.parcelize.Parcelize import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.events.model.EventType.generateBeaconInfoStateEventType import org.matrix.android.sdk.api.session.events.model.toContent -import org.matrix.android.sdk.api.session.room.model.BeaconInfo -import org.matrix.android.sdk.api.session.room.model.LiveLocationBeaconContent +import org.matrix.android.sdk.api.session.room.model.livelocation.BeaconInfo +import org.matrix.android.sdk.api.session.room.model.livelocation.LiveLocationBeaconContent import timber.log.Timber import java.util.Timer import java.util.TimerTask @@ -83,7 +83,7 @@ class LocationSharingService : VectorService(), LocationTracker.Callback { activeSessionHolder .getSafeActiveSession() ?.let { session -> - session.coroutineScope.launch { + session.coroutineScope.launch(session.coroutineDispatchers.io) { sendBeaconInfo(session, roomArgs) } } From 273b4816db148447187ad94d0e90667c2c4f41c5 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Mon, 4 Apr 2022 12:03:43 +0300 Subject: [PATCH 7/7] Fix lint error. --- .../room/model/livelocation/LiveLocationBeaconContent.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/livelocation/LiveLocationBeaconContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/livelocation/LiveLocationBeaconContent.kt index e07df14aee..e08d5b629b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/livelocation/LiveLocationBeaconContent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/livelocation/LiveLocationBeaconContent.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 New Vector Ltd + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License.