Merge pull request #5869 from vector-im/feature/mna/PSF-884-live-location-aggregation

[Live location sharing] Improve aggregation process of events
This commit is contained in:
Benoit Marty 2022-05-04 11:11:39 +02:00 committed by GitHub
commit b5a0c944d1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 414 additions and 152 deletions

1
changelog.d/5862.wip Normal file
View file

@ -0,0 +1 @@
[Live location sharing] Improve aggregation process of events

View file

@ -15,9 +15,12 @@
*/
package org.matrix.android.sdk.api.session.room.model
import org.matrix.android.sdk.api.session.room.model.livelocation.LiveLocationShareAggregatedSummary
data class EventAnnotationsSummary(
val reactionsSummary: List<ReactionAggregatedSummary> = emptyList(),
val editSummary: EditAggregatedSummary? = null,
val pollResponseSummary: PollResponseAggregatedSummary? = null,
val referencesAggregatedSummary: ReferencesAggregatedSummary? = null
val referencesAggregatedSummary: ReferencesAggregatedSummary? = null,
val liveLocationShareAggregatedSummary: LiveLocationShareAggregatedSummary? = null,
)

View file

@ -0,0 +1,28 @@
/*
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.api.session.room.model.livelocation
import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconLocationDataContent
/**
* Aggregation info concerning a live location share.
*/
data class LiveLocationShareAggregatedSummary(
val isActive: Boolean?,
val endOfLiveTimestampMillis: Long?,
val lastLocationDataContent: MessageBeaconLocationDataContent?,
)

View file

@ -14,25 +14,28 @@
* limitations under the License.
*/
package org.matrix.android.sdk.api.session.room.model.livelocation
package org.matrix.android.sdk.api.session.room.model.message
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import org.matrix.android.sdk.api.session.events.model.Content
import org.matrix.android.sdk.api.session.room.model.message.LocationAsset
import org.matrix.android.sdk.api.session.room.model.message.LocationAssetType
import org.matrix.android.sdk.api.session.room.model.message.MessageContent
import org.matrix.android.sdk.api.session.room.model.message.MessageLiveLocationContent
import org.matrix.android.sdk.api.session.room.model.message.MessageType
import org.matrix.android.sdk.api.session.room.model.relation.RelationDefaultContent
/**
* Content of the state event of type
* [EventType.STATE_ROOM_BEACON_INFO][org.matrix.android.sdk.api.session.events.model.EventType.STATE_ROOM_BEACON_INFO]
*
* It contains general info related to a live location share.
* Locations are sent in a different message related to the state event.
* See [MessageBeaconLocationDataContent][org.matrix.android.sdk.api.session.room.model.message.MessageBeaconLocationDataContent]
*/
@JsonClass(generateAdapter = true)
data class LiveLocationBeaconContent(
data class MessageBeaconInfoContent(
/**
* Local message type, not from server
*/
@Transient
override val msgType: String = MessageType.MSGTYPE_LIVE_LOCATION_STATE,
override val msgType: String = MessageType.MSGTYPE_BEACON_INFO,
@Json(name = "body") override val body: String = "",
@Json(name = "m.relates_to") override val relatesTo: RelationDefaultContent? = null,
@ -54,26 +57,16 @@ data class LiveLocationBeaconContent(
/**
* Beacon creation timestamp.
*/
@Json(name = "org.matrix.msc3488.ts") val unstableTimestampAsMilliseconds: Long? = null,
@Json(name = "m.ts") val timestampAsMilliseconds: Long? = null,
@Json(name = "org.matrix.msc3488.ts") val unstableTimestampMillis: Long? = null,
@Json(name = "m.ts") val timestampMillis: Long? = null,
/**
* Live location asset type.
*/
@Json(name = "org.matrix.msc3488.asset") val unstableLocationAsset: LocationAsset = LocationAsset(LocationAssetType.SELF),
@Json(name = "m.asset") val locationAsset: LocationAsset? = null,
/**
* Client side tracking of the last location
*/
var lastLocationContent: MessageLiveLocationContent? = null,
/**
* Client side tracking of whether the beacon has timed out.
*/
var hasTimedOut: Boolean = false
) : MessageContent {
fun getBestTimestampAsMilliseconds() = timestampAsMilliseconds ?: unstableTimestampAsMilliseconds
fun getBestTimestampMillis() = timestampMillis ?: unstableTimestampMillis
fun getBestLocationAsset() = locationAsset ?: unstableLocationAsset
}

View file

@ -21,13 +21,21 @@ import com.squareup.moshi.JsonClass
import org.matrix.android.sdk.api.session.events.model.Content
import org.matrix.android.sdk.api.session.room.model.relation.RelationDefaultContent
/**
* Content of the state event of type
* [EventType.BEACON_LOCATION_DATA][org.matrix.android.sdk.api.session.events.model.EventType.BEACON_LOCATION_DATA]
*
* It contains location data related to a live location share.
* It is related to the state event that originally started the live.
* See [MessageBeaconInfoContent][org.matrix.android.sdk.api.session.room.model.message.MessageBeaconInfoContent]
*/
@JsonClass(generateAdapter = true)
data class MessageLiveLocationContent(
data class MessageBeaconLocationDataContent(
/**
* Local message type, not from server
*/
@Transient
override val msgType: String = MessageType.MSGTYPE_LIVE_LOCATION,
override val msgType: String = MessageType.MSGTYPE_BEACON_LOCATION_DATA,
@Json(name = "body") override val body: String = "",
@Json(name = "m.relates_to") override val relatesTo: RelationDefaultContent? = null,
@ -42,11 +50,11 @@ data class MessageLiveLocationContent(
/**
* Exact time that the data in the event refers to (milliseconds since the UNIX epoch)
*/
@Json(name = "org.matrix.msc3488.ts") val unstableTimestampAsMilliseconds: Long? = null,
@Json(name = "m.ts") val timestampAsMilliseconds: Long? = null
@Json(name = "org.matrix.msc3488.ts") val unstableTimestampMillis: Long? = null,
@Json(name = "m.ts") val timestampMillis: Long? = null
) : MessageContent {
fun getBestLocationInfo() = locationInfo ?: unstableLocationInfo
fun getBestTimestampAsMilliseconds() = timestampAsMilliseconds ?: unstableTimestampAsMilliseconds
fun getBestTimestampMillis() = timestampMillis ?: unstableTimestampMillis
}

View file

@ -49,8 +49,8 @@ data class MessageLocationContent(
/**
* Exact time that the data in the event refers to (milliseconds since the UNIX epoch)
*/
@Json(name = "org.matrix.msc3488.ts") val unstableTs: Long? = null,
@Json(name = "m.ts") val ts: Long? = null,
@Json(name = "org.matrix.msc3488.ts") val unstableTimestampMillis: Long? = null,
@Json(name = "m.ts") val timestampMillis: Long? = null,
@Json(name = "org.matrix.msc1767.text") val unstableText: String? = null,
@Json(name = "m.text") val text: String? = null,
/**
@ -66,7 +66,7 @@ data class MessageLocationContent(
fun getBestLocationInfo() = locationInfo ?: unstableLocationInfo
fun getBestTs() = ts ?: unstableTs
fun getBestTimestampMillis() = timestampMillis ?: unstableTimestampMillis
fun getBestText() = text ?: unstableText

View file

@ -41,6 +41,6 @@ object MessageType {
const val MSGTYPE_SNOWFALL = "io.element.effect.snowfall"
// Fake message types for live location events to be able to inherit them from MessageContent
const val MSGTYPE_LIVE_LOCATION_STATE = "org.matrix.android.sdk.livelocation.state"
const val MSGTYPE_LIVE_LOCATION = "org.matrix.android.sdk.livelocation"
const val MSGTYPE_BEACON_INFO = "org.matrix.android.sdk.beacon.info"
const val MSGTYPE_BEACON_LOCATION_DATA = "org.matrix.android.sdk.beacon.location.data"
}

View file

@ -29,7 +29,7 @@ import org.matrix.android.sdk.api.session.events.model.isSticker
import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.room.model.EventAnnotationsSummary
import org.matrix.android.sdk.api.session.room.model.ReadReceipt
import org.matrix.android.sdk.api.session.room.model.livelocation.LiveLocationBeaconContent
import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconInfoContent
import org.matrix.android.sdk.api.session.room.model.message.MessageContent
import org.matrix.android.sdk.api.session.room.model.message.MessagePollContent
import org.matrix.android.sdk.api.session.room.model.message.MessageStickerContent
@ -139,7 +139,7 @@ fun TimelineEvent.getLastMessageContent(): MessageContent? {
return when (root.getClearType()) {
EventType.STICKER -> root.getClearContent().toModel<MessageStickerContent>()
in EventType.POLL_START -> (annotations?.editSummary?.latestContent ?: root.getClearContent()).toModel<MessagePollContent>()
in EventType.STATE_ROOM_BEACON_INFO -> (annotations?.editSummary?.latestContent ?: root.getClearContent()).toModel<LiveLocationBeaconContent>()
in EventType.STATE_ROOM_BEACON_INFO -> (annotations?.editSummary?.latestContent ?: root.getClearContent()).toModel<MessageBeaconInfoContent>()
else -> (annotations?.editSummary?.latestContent ?: root.getClearContent()).toModel()
}
}

View file

@ -44,6 +44,7 @@ import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo023
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo024
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo025
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo026
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo027
import org.matrix.android.sdk.internal.util.Normalizer
import timber.log.Timber
import javax.inject.Inject
@ -58,7 +59,7 @@ internal class RealmSessionStoreMigration @Inject constructor(
override fun equals(other: Any?) = other is RealmSessionStoreMigration
override fun hashCode() = 1000
val schemaVersion = 26L
val schemaVersion = 27L
override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) {
Timber.d("Migrating Realm Session from $oldVersion to $newVersion")
@ -89,5 +90,6 @@ internal class RealmSessionStoreMigration @Inject constructor(
if (oldVersion < 24) MigrateSessionTo024(realm).perform()
if (oldVersion < 25) MigrateSessionTo025(realm).perform()
if (oldVersion < 26) MigrateSessionTo026(realm).perform()
if (oldVersion < 27) MigrateSessionTo027(realm).perform()
}
}

View file

@ -56,8 +56,10 @@ internal object EventAnnotationsSummaryMapper {
},
pollResponseSummary = annotationsSummary.pollResponseSummary?.let {
PollResponseAggregatedSummaryEntityMapper.map(it)
},
liveLocationShareAggregatedSummary = annotationsSummary.liveLocationShareAggregatedSummary?.let {
LiveLocationShareAggregatedSummaryMapper.map(it)
}
)
}
}

View file

@ -0,0 +1,33 @@
/*
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.database.mapper
import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.room.model.livelocation.LiveLocationShareAggregatedSummary
import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconLocationDataContent
import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntity
internal object LiveLocationShareAggregatedSummaryMapper {
fun map(entity: LiveLocationShareAggregatedSummaryEntity): LiveLocationShareAggregatedSummary {
return LiveLocationShareAggregatedSummary(
isActive = entity.isActive,
endOfLiveTimestampMillis = entity.endOfLiveTimestampMillis,
lastLocationDataContent = ContentMapper.map(entity.lastLocationContent).toModel<MessageBeaconLocationDataContent>()
)
}
}

View file

@ -0,0 +1,46 @@
/*
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.database.migration
import io.realm.DynamicRealm
import io.realm.FieldAttribute
import org.matrix.android.sdk.internal.database.model.EventAnnotationsSummaryEntityFields
import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntityFields
import org.matrix.android.sdk.internal.util.database.RealmMigrator
/**
* Migrating to:
* Live location sharing aggregated summary
*/
internal class MigrateSessionTo027(realm: DynamicRealm) : RealmMigrator(realm, 27) {
override fun doMigrate(realm: DynamicRealm) {
val liveLocationSummaryEntity = realm.schema.get("LiveLocationShareAggregatedSummaryEntity")
?: realm.schema.create("LiveLocationShareAggregatedSummaryEntity")
.addField(LiveLocationShareAggregatedSummaryEntityFields.EVENT_ID, String::class.java, FieldAttribute.REQUIRED)
.addField(LiveLocationShareAggregatedSummaryEntityFields.ROOM_ID, String::class.java, FieldAttribute.REQUIRED)
.addField(LiveLocationShareAggregatedSummaryEntityFields.IS_ACTIVE, Boolean::class.java)
.setNullable(LiveLocationShareAggregatedSummaryEntityFields.IS_ACTIVE, true)
.addField(LiveLocationShareAggregatedSummaryEntityFields.END_OF_LIVE_TIMESTAMP_MILLIS, Long::class.java)
.setNullable(LiveLocationShareAggregatedSummaryEntityFields.END_OF_LIVE_TIMESTAMP_MILLIS, true)
.addField(LiveLocationShareAggregatedSummaryEntityFields.LAST_LOCATION_CONTENT, String::class.java)
?: return
realm.schema.get("EventAnnotationsSummaryEntity")
?.addRealmObjectField(EventAnnotationsSummaryEntityFields.LIVE_LOCATION_SHARE_AGGREGATED_SUMMARY.`$`, liveLocationSummaryEntity)
}
}

View file

@ -18,6 +18,7 @@ package org.matrix.android.sdk.internal.database.model
import io.realm.RealmList
import io.realm.RealmObject
import io.realm.annotations.PrimaryKey
import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntity
import timber.log.Timber
internal open class EventAnnotationsSummaryEntity(
@ -27,7 +28,8 @@ internal open class EventAnnotationsSummaryEntity(
var reactionsSummary: RealmList<ReactionAggregatedSummaryEntity> = RealmList(),
var editSummary: EditAggregatedSummaryEntity? = null,
var referencesSummaryEntity: ReferencesAggregatedSummaryEntity? = null,
var pollResponseSummary: PollResponseAggregatedSummaryEntity? = null
var pollResponseSummary: PollResponseAggregatedSummaryEntity? = null,
var liveLocationShareAggregatedSummary: LiveLocationShareAggregatedSummaryEntity? = null,
) : RealmObject() {
/**

View file

@ -17,6 +17,7 @@
package org.matrix.android.sdk.internal.database.model
import io.realm.annotations.RealmModule
import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntity
import org.matrix.android.sdk.internal.database.model.presence.UserPresenceEntity
import org.matrix.android.sdk.internal.database.model.threads.ThreadSummaryEntity
@ -47,6 +48,7 @@ import org.matrix.android.sdk.internal.database.model.threads.ThreadSummaryEntit
EditAggregatedSummaryEntity::class,
EditionOfEvent::class,
PollResponseAggregatedSummaryEntity::class,
LiveLocationShareAggregatedSummaryEntity::class,
ReferencesAggregatedSummaryEntity::class,
PushRulesEntity::class,
PushRuleEntity::class,

View file

@ -0,0 +1,45 @@
/*
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.database.model.livelocation
import io.realm.RealmObject
import io.realm.annotations.PrimaryKey
/**
* Aggregation info concerning a live location share.
*/
internal open class LiveLocationShareAggregatedSummaryEntity(
/**
* Event id of the event that started the live.
*/
@PrimaryKey
var eventId: String = "",
var roomId: String = "",
var isActive: Boolean? = null,
var endOfLiveTimestampMillis: Long? = null,
/**
* For now we persist this as a JSON for greater flexibility
* @see [org.matrix.android.sdk.api.session.room.model.message.MessageBeaconLocationDataContent]
*/
var lastLocationContent: String? = null,
) : RealmObject() {
companion object
}

View file

@ -0,0 +1,57 @@
/*
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.database.query
import io.realm.Realm
import io.realm.RealmQuery
import io.realm.kotlin.where
import org.matrix.android.sdk.internal.database.model.EventAnnotationsSummaryEntity
import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntity
import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntityFields
internal fun LiveLocationShareAggregatedSummaryEntity.Companion.where(
realm: Realm,
roomId: String,
eventId: String,
): RealmQuery<LiveLocationShareAggregatedSummaryEntity> {
return realm.where<LiveLocationShareAggregatedSummaryEntity>()
.equalTo(LiveLocationShareAggregatedSummaryEntityFields.ROOM_ID, roomId)
.equalTo(LiveLocationShareAggregatedSummaryEntityFields.EVENT_ID, eventId)
}
internal fun LiveLocationShareAggregatedSummaryEntity.Companion.create(
realm: Realm,
roomId: String,
eventId: String,
): LiveLocationShareAggregatedSummaryEntity {
val obj = realm.createObject(LiveLocationShareAggregatedSummaryEntity::class.java, eventId).apply {
this.roomId = roomId
}
val annotationSummary = EventAnnotationsSummaryEntity.getOrCreate(realm, roomId = roomId, eventId = eventId)
annotationSummary.liveLocationShareAggregatedSummary = obj
return obj
}
internal fun LiveLocationShareAggregatedSummaryEntity.Companion.getOrCreate(
realm: Realm,
roomId: String,
eventId: String,
): LiveLocationShareAggregatedSummaryEntity {
return LiveLocationShareAggregatedSummaryEntity.where(realm, roomId, eventId).findFirst()
?: LiveLocationShareAggregatedSummaryEntity.create(realm, roomId, eventId)
}

View file

@ -33,9 +33,10 @@ import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
import org.matrix.android.sdk.api.session.room.model.ReferencesAggregatedContent
import org.matrix.android.sdk.api.session.room.model.VoteInfo
import org.matrix.android.sdk.api.session.room.model.VoteSummary
import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconInfoContent
import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconLocationDataContent
import org.matrix.android.sdk.api.session.room.model.message.MessageContent
import org.matrix.android.sdk.api.session.room.model.message.MessageEndPollContent
import org.matrix.android.sdk.api.session.room.model.message.MessageLiveLocationContent
import org.matrix.android.sdk.api.session.room.model.message.MessagePollContent
import org.matrix.android.sdk.api.session.room.model.message.MessagePollResponseContent
import org.matrix.android.sdk.api.session.room.model.message.MessageRelationContent
@ -91,7 +92,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
// EventType.KEY_VERIFICATION_READY,
EventType.KEY_VERIFICATION_KEY,
EventType.ENCRYPTED
) + EventType.POLL_START + EventType.POLL_RESPONSE + EventType.POLL_END + EventType.BEACON_LOCATION_DATA
) + EventType.POLL_START + EventType.POLL_RESPONSE + EventType.POLL_END + EventType.STATE_ROOM_BEACON_INFO + EventType.BEACON_LOCATION_DATA
override fun shouldProcess(eventId: String, eventType: String, insertType: EventInsertType): Boolean {
return allowedTypes.contains(eventType)
@ -106,12 +107,12 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
}
val isLocalEcho = LocalEcho.isLocalEchoId(event.eventId ?: "")
when (event.type) {
EventType.REACTION -> {
EventType.REACTION -> {
// we got a reaction!!
Timber.v("###REACTION in room $roomId , reaction eventID ${event.eventId}")
handleReaction(realm, event, roomId, isLocalEcho)
}
EventType.MESSAGE -> {
EventType.MESSAGE -> {
if (event.unsignedData?.relations?.annotations != null) {
Timber.v("###REACTION Aggregation in room $roomId for event ${event.eventId}")
handleInitialAggregatedRelations(realm, event, roomId, event.unsignedData.relations.annotations)
@ -137,7 +138,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
EventType.KEY_VERIFICATION_START,
EventType.KEY_VERIFICATION_MAC,
EventType.KEY_VERIFICATION_READY,
EventType.KEY_VERIFICATION_KEY -> {
EventType.KEY_VERIFICATION_KEY -> {
Timber.v("## SAS REF in room $roomId for event ${event.eventId}")
event.content.toModel<MessageRelationContent>()?.relatesTo?.let {
if (it.type == RelationType.REFERENCE && it.eventId != null) {
@ -146,7 +147,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
}
}
EventType.ENCRYPTED -> {
EventType.ENCRYPTED -> {
// Relation type is in clear
val encryptedEventContent = event.content.toModel<EncryptedEventContent>()
if (encryptedEventContent?.relatesTo?.type == RelationType.REPLACE ||
@ -189,8 +190,8 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
}
}
in EventType.BEACON_LOCATION_DATA -> {
event.content.toModel<MessageLiveLocationContent>(catchError = true)?.let {
liveLocationAggregationProcessor.handleLiveLocation(realm, event, it, roomId, isLocalEcho)
event.getClearContent().toModel<MessageBeaconLocationDataContent>(catchError = true)?.let {
liveLocationAggregationProcessor.handleBeaconLocationData(realm, event, it, roomId, isLocalEcho)
}
}
}
@ -213,7 +214,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
// }
// }
}
EventType.REDACTION -> {
EventType.REDACTION -> {
val eventToPrune = event.redacts?.let { EventEntity.where(realm, eventId = it).findFirst() }
?: return
when (eventToPrune.type) {
@ -233,7 +234,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
}
}
}
in EventType.POLL_START -> {
in EventType.POLL_START -> {
val content: MessagePollContent? = event.content.toModel()
if (content?.relatesTo?.type == RelationType.REPLACE) {
Timber.v("###REPLACE in room $roomId for event ${event.eventId}")
@ -241,22 +242,22 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
handleReplace(realm, event, content, roomId, isLocalEcho)
}
}
in EventType.POLL_RESPONSE -> {
in EventType.POLL_RESPONSE -> {
event.content.toModel<MessagePollResponseContent>(catchError = true)?.let {
handleResponse(realm, event, it, roomId, isLocalEcho)
}
}
in EventType.POLL_END -> {
in EventType.POLL_END -> {
event.content.toModel<MessageEndPollContent>(catchError = true)?.let {
handleEndPoll(realm, event, it, roomId, isLocalEcho)
}
}
in EventType.BEACON_LOCATION_DATA -> {
event.content.toModel<MessageLiveLocationContent>(catchError = true)?.let {
liveLocationAggregationProcessor.handleLiveLocation(realm, event, it, roomId, isLocalEcho)
in EventType.STATE_ROOM_BEACON_INFO -> {
event.content.toModel<MessageBeaconInfoContent>(catchError = true)?.let {
liveLocationAggregationProcessor.handleBeaconInfo(realm, event, it, roomId, isLocalEcho)
}
}
else -> Timber.v("UnHandled event ${event.eventId}")
else -> Timber.v("UnHandled event ${event.eventId}")
}
} catch (t: Throwable) {
Timber.e(t, "## Should not happen ")
@ -325,7 +326,8 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
totalVotes = 0,
winnerVoteCount = 0,
)
.toContent())
.toContent()
)
}
val txId = event.unsignedData?.transactionId
@ -729,11 +731,13 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
EventType.KEY_VERIFICATION_READY,
EventType.KEY_VERIFICATION_KEY,
EventType.KEY_VERIFICATION_MAC -> currentState.toState(VerificationState.WAITING)
EventType.KEY_VERIFICATION_CANCEL -> currentState.toState(if (event.senderId == userId) {
VerificationState.CANCELED_BY_ME
} else {
VerificationState.CANCELED_BY_OTHER
})
EventType.KEY_VERIFICATION_CANCEL -> currentState.toState(
if (event.senderId == userId) {
VerificationState.CANCELED_BY_ME
} else {
VerificationState.CANCELED_BY_OTHER
}
)
EventType.KEY_VERIFICATION_DONE -> currentState.toState(VerificationState.DONE)
else -> VerificationState.REQUEST
}

View file

@ -17,69 +17,78 @@
package org.matrix.android.sdk.internal.session.room.aggregation.livelocation
import io.realm.Realm
import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.extensions.orTrue
import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.events.model.toContent
import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.room.model.livelocation.LiveLocationBeaconContent
import org.matrix.android.sdk.api.session.room.model.message.MessageLiveLocationContent
import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconInfoContent
import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconLocationDataContent
import org.matrix.android.sdk.internal.database.mapper.ContentMapper
import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntity
import org.matrix.android.sdk.internal.database.query.getOrNull
import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntity
import org.matrix.android.sdk.internal.database.query.getOrCreate
import timber.log.Timber
import javax.inject.Inject
internal class DefaultLiveLocationAggregationProcessor @Inject constructor() : LiveLocationAggregationProcessor {
override fun handleLiveLocation(realm: Realm, event: Event, content: MessageLiveLocationContent, roomId: String, isLocalEcho: Boolean) {
val locationSenderId = event.senderId ?: return
// We shouldn't process local echos
if (isLocalEcho) {
override fun handleBeaconInfo(realm: Realm, event: Event, content: MessageBeaconInfoContent, roomId: String, isLocalEcho: Boolean) {
if (event.senderId.isNullOrEmpty() || isLocalEcho) {
return
}
// A beacon info state event has to be sent before sending location
// TODO handle missing check of m_relatesTo field
var beaconInfoEntity: CurrentStateEventEntity? = null
val eventTypesIterator = EventType.STATE_ROOM_BEACON_INFO.iterator()
while (beaconInfoEntity == null && eventTypesIterator.hasNext()) {
beaconInfoEntity = CurrentStateEventEntity.getOrNull(realm, roomId, locationSenderId, eventTypesIterator.next())
}
if (beaconInfoEntity == null) {
Timber.v("## LIVE LOCATION. There is not any beacon info which should be emitted before sending location updates")
return
}
val beaconInfoContent = ContentMapper.map(beaconInfoEntity.root?.content)?.toModel<LiveLocationBeaconContent>(catchError = true)
if (beaconInfoContent == null) {
Timber.v("## LIVE LOCATION. Beacon info content is invalid")
return
}
// Check if live location is ended
if (!beaconInfoContent.isLive.orFalse()) {
Timber.v("## LIVE LOCATION. Beacon info is not live anymore")
return
}
// Check if beacon info is outdated
if (isBeaconInfoOutdated(beaconInfoContent, content)) {
Timber.v("## LIVE LOCATION. Beacon info has timeout")
beaconInfoContent.hasTimedOut = true
val targetEventId = if (content.isLive.orTrue()) {
event.eventId
} else {
beaconInfoContent.lastLocationContent = content
// when live is set to false, we use the id of the event that should have been replaced
event.unsignedData?.replacesState
}
beaconInfoEntity.root?.content = ContentMapper.map(beaconInfoContent.toContent())
if (targetEventId.isNullOrEmpty()) {
Timber.w("no target event id found for the beacon content")
return
}
val aggregatedSummary = LiveLocationShareAggregatedSummaryEntity.getOrCreate(
realm = realm,
roomId = roomId,
eventId = targetEventId
)
Timber.d("updating summary of id=$targetEventId with isLive=${content.isLive}")
aggregatedSummary.endOfLiveTimestampMillis = content.getBestTimestampMillis()?.let { it + (content.timeout ?: 0) }
aggregatedSummary.isActive = content.isLive
}
private fun isBeaconInfoOutdated(beaconInfoContent: LiveLocationBeaconContent,
liveLocationContent: MessageLiveLocationContent): Boolean {
val beaconInfoStartTime = beaconInfoContent.getBestTimestampAsMilliseconds() ?: 0
val liveLocationEventTime = liveLocationContent.getBestTimestampAsMilliseconds() ?: 0
val timeout = beaconInfoContent.timeout ?: 0
return liveLocationEventTime - beaconInfoStartTime > timeout
override fun handleBeaconLocationData(realm: Realm, event: Event, content: MessageBeaconLocationDataContent, roomId: String, isLocalEcho: Boolean) {
if (event.senderId.isNullOrEmpty() || isLocalEcho) {
return
}
val targetEventId = content.relatesTo?.eventId
if (targetEventId.isNullOrEmpty()) {
Timber.w("no target event id found for the live location content")
return
}
val aggregatedSummary = LiveLocationShareAggregatedSummaryEntity.getOrCreate(
realm = realm,
roomId = roomId,
eventId = targetEventId
)
val updatedLocationTimestamp = content.getBestTimestampMillis() ?: 0
val currentLocationTimestamp = ContentMapper
.map(aggregatedSummary.lastLocationContent)
.toModel<MessageBeaconLocationDataContent>()
?.getBestTimestampMillis()
?: 0
if (updatedLocationTimestamp.isMoreRecentThan(currentLocationTimestamp)) {
Timber.d("updating last location of the summary of id=$targetEventId")
aggregatedSummary.lastLocationContent = ContentMapper.map(content.toContent())
}
}
private fun Long.isMoreRecentThan(timestamp: Long) = this > timestamp
}

View file

@ -18,12 +18,23 @@ package org.matrix.android.sdk.internal.session.room.aggregation.livelocation
import io.realm.Realm
import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.room.model.message.MessageLiveLocationContent
import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconInfoContent
import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconLocationDataContent
internal interface LiveLocationAggregationProcessor {
fun handleLiveLocation(realm: Realm,
event: Event,
content: MessageLiveLocationContent,
roomId: String,
isLocalEcho: Boolean)
fun handleBeaconInfo(
realm: Realm,
event: Event,
content: MessageBeaconInfoContent,
roomId: String,
isLocalEcho: Boolean,
)
fun handleBeaconLocationData(
realm: Realm,
event: Event,
content: MessageBeaconLocationDataContent,
roomId: String,
isLocalEcho: Boolean,
)
}

View file

@ -37,13 +37,13 @@ import org.matrix.android.sdk.api.session.room.model.message.LocationAsset
import org.matrix.android.sdk.api.session.room.model.message.LocationAssetType
import org.matrix.android.sdk.api.session.room.model.message.LocationInfo
import org.matrix.android.sdk.api.session.room.model.message.MessageAudioContent
import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconLocationDataContent
import org.matrix.android.sdk.api.session.room.model.message.MessageContent
import org.matrix.android.sdk.api.session.room.model.message.MessageContentWithFormattedBody
import org.matrix.android.sdk.api.session.room.model.message.MessageEndPollContent
import org.matrix.android.sdk.api.session.room.model.message.MessageFileContent
import org.matrix.android.sdk.api.session.room.model.message.MessageFormat
import org.matrix.android.sdk.api.session.room.model.message.MessageImageContent
import org.matrix.android.sdk.api.session.room.model.message.MessageLiveLocationContent
import org.matrix.android.sdk.api.session.room.model.message.MessageLocationContent
import org.matrix.android.sdk.api.session.room.model.message.MessagePollContent
import org.matrix.android.sdk.api.session.room.model.message.MessagePollResponseContent
@ -71,7 +71,6 @@ import org.matrix.android.sdk.internal.session.content.ThumbnailExtractor
import org.matrix.android.sdk.internal.session.permalinks.PermalinkFactory
import org.matrix.android.sdk.internal.session.room.send.pills.TextPillsUtils
import java.util.UUID
import java.util.concurrent.TimeUnit
import javax.inject.Inject
/**
@ -124,7 +123,8 @@ internal class LocalEchoEventFactory @Inject constructor(
newBodyAutoMarkdown: Boolean,
msgType: String,
compatibilityText: String): Event {
return createMessageEvent(roomId,
return createMessageEvent(
roomId,
MessageTextContent(
msgType = msgType,
body = compatibilityText,
@ -132,7 +132,8 @@ internal class LocalEchoEventFactory @Inject constructor(
newContent = createTextContent(newBodyText, newBodyAutoMarkdown)
.toMessageTextContent(msgType)
.toContent()
))
)
)
}
private fun createPollContent(question: String,
@ -188,7 +189,8 @@ internal class LocalEchoEventFactory @Inject constructor(
eventId = localId,
type = EventType.POLL_RESPONSE.first(),
content = content.toContent(),
unsignedData = UnsignedData(age = null, transactionId = localId))
unsignedData = UnsignedData(age = null, transactionId = localId)
)
}
fun createPollEvent(roomId: String,
@ -204,7 +206,8 @@ internal class LocalEchoEventFactory @Inject constructor(
eventId = localId,
type = EventType.POLL_START.first(),
content = content.toContent(),
unsignedData = UnsignedData(age = null, transactionId = localId))
unsignedData = UnsignedData(age = null, transactionId = localId)
)
}
fun createEndPollEvent(roomId: String,
@ -223,7 +226,8 @@ internal class LocalEchoEventFactory @Inject constructor(
eventId = localId,
type = EventType.POLL_END.first(),
content = content.toContent(),
unsignedData = UnsignedData(age = null, transactionId = localId))
unsignedData = UnsignedData(age = null, transactionId = localId)
)
}
fun createLocationEvent(roomId: String,
@ -238,7 +242,7 @@ internal class LocalEchoEventFactory @Inject constructor(
body = geoUri,
unstableLocationInfo = LocationInfo(geoUri = geoUri, description = geoUri),
unstableLocationAsset = LocationAsset(type = assetType),
unstableTs = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()),
unstableTimestampMillis = System.currentTimeMillis(),
unstableText = geoUri
)
return createMessageEvent(roomId, content)
@ -250,14 +254,14 @@ internal class LocalEchoEventFactory @Inject constructor(
longitude: Double,
uncertainty: Double?): Event {
val geoUri = buildGeoUri(latitude, longitude, uncertainty)
val content = MessageLiveLocationContent(
val content = MessageBeaconLocationDataContent(
body = geoUri,
relatesTo = RelationDefaultContent(
type = RelationType.REFERENCE,
eventId = beaconInfoEventId
),
unstableLocationInfo = LocationInfo(geoUri = geoUri, description = geoUri),
unstableTimestampAsMilliseconds = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()),
unstableTimestampMillis = System.currentTimeMillis(),
)
val localId = LocalEcho.createLocalEchoId()
return Event(
@ -267,7 +271,8 @@ internal class LocalEchoEventFactory @Inject constructor(
eventId = localId,
type = EventType.BEACON_LOCATION_DATA.first(),
content = content.toContent(),
unsignedData = UnsignedData(age = null, transactionId = localId))
unsignedData = UnsignedData(age = null, transactionId = localId)
)
}
fun createReplaceTextOfReply(roomId: String,
@ -297,7 +302,8 @@ internal class LocalEchoEventFactory @Inject constructor(
//
val replyFallback = buildReplyFallback(body, originalEvent.root.senderId ?: "", newBodyText)
return createMessageEvent(roomId,
return createMessageEvent(
roomId,
MessageTextContent(
msgType = msgType,
body = compatibilityText,
@ -309,7 +315,8 @@ internal class LocalEchoEventFactory @Inject constructor(
formattedBody = replyFormatted
)
.toContent()
))
)
)
}
fun createMediaEvent(roomId: String,
@ -341,7 +348,8 @@ internal class LocalEchoEventFactory @Inject constructor(
eventId = localId,
type = EventType.REACTION,
content = content.toContent(),
unsignedData = UnsignedData(age = null, transactionId = localId))
unsignedData = UnsignedData(age = null, transactionId = localId)
)
}
private fun createImageEvent(roomId: String, attachment: ContentAttachmentData, rootThreadEventId: String?): Event {
@ -532,8 +540,10 @@ internal class LocalEchoEventFactory @Inject constructor(
content.toThreadTextContent(
rootThreadEventId = rootThreadEventId,
latestThreadEventId = localEchoRepository.getLatestThreadEvent(rootThreadEventId),
msgType = msgType)
.toContent())
msgType = msgType
)
.toContent()
)
}
private fun dummyOriginServerTs(): Long {
@ -582,7 +592,9 @@ internal class LocalEchoEventFactory @Inject constructor(
relatesTo = generateReplyRelationContent(
eventId = eventId,
rootThreadEventId = rootThreadEventId,
showInThread = showInThread))
showInThread = showInThread
)
)
return createMessageEvent(roomId, content)
}
@ -605,7 +617,8 @@ internal class LocalEchoEventFactory @Inject constructor(
eventId = it,
isFallingBack = showInThread,
// False when is a rich reply from within a thread, and true when is a reply that should be visible from threads
inReplyTo = ReplyToContent(eventId = eventId))
inReplyTo = ReplyToContent(eventId = eventId)
)
} ?: RelationDefaultContent(null, null, ReplyToContent(eventId = eventId))
private fun buildFormattedReply(permalink: String, userLink: String, userId: String, bodyFormatted: String, newBodyFormatted: String): String {
@ -740,13 +753,15 @@ internal class LocalEchoEventFactory @Inject constructor(
.toThreadTextContent(
rootThreadEventId = rootThreadEventId,
latestThreadEventId = localEchoRepository.getLatestThreadEvent(rootThreadEventId),
msgType = MessageType.MSGTYPE_TEXT)
msgType = MessageType.MSGTYPE_TEXT
)
)
} else {
createFormattedTextEvent(
roomId,
markdownParser.parse(quoteText, force = true, advanced = autoMarkdown),
MessageType.MSGTYPE_TEXT)
MessageType.MSGTYPE_TEXT
)
}
}

View file

@ -33,7 +33,7 @@ import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibility
import org.matrix.android.sdk.api.session.room.model.RoomJoinRules
import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesAllowEntry
import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesContent
import org.matrix.android.sdk.api.session.room.model.livelocation.LiveLocationBeaconContent
import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconInfoContent
import org.matrix.android.sdk.api.session.room.state.StateService
import org.matrix.android.sdk.api.util.JsonDict
import org.matrix.android.sdk.api.util.MimeTypes
@ -192,7 +192,7 @@ internal class DefaultStateService @AssistedInject constructor(@Assisted private
override suspend fun stopLiveLocation(userId: String) {
getLiveLocationBeaconInfo(userId, true)?.let { beaconInfoStateEvent ->
beaconInfoStateEvent.getClearContent()?.toModel<LiveLocationBeaconContent>()?.let { content ->
beaconInfoStateEvent.getClearContent()?.toModel<MessageBeaconInfoContent>()?.let { content ->
val updatedContent = content.copy(isLive = false).toContent()
beaconInfoStateEvent.stateKey?.let {
@ -217,7 +217,7 @@ internal class DefaultStateService @AssistedInject constructor(@Assisted private
}
.firstOrNull { beaconInfoEvent ->
!filterOnlyLive ||
beaconInfoEvent.getClearContent()?.toModel<LiveLocationBeaconContent>()?.isLive.orFalse()
beaconInfoEvent.getClearContent()?.toModel<MessageBeaconInfoContent>()?.isLive.orFalse()
}
}
}

View file

@ -24,7 +24,7 @@ import im.vector.app.features.home.room.detail.timeline.item.AbsMessageItem
import im.vector.app.features.home.room.detail.timeline.item.MessageLiveLocationStartItem
import im.vector.app.features.home.room.detail.timeline.item.MessageLiveLocationStartItem_
import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.session.room.model.livelocation.LiveLocationBeaconContent
import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconInfoContent
import javax.inject.Inject
class LiveLocationMessageItemFactory @Inject constructor(
@ -34,19 +34,20 @@ class LiveLocationMessageItemFactory @Inject constructor(
) {
fun create(
liveLocationContent: LiveLocationBeaconContent,
beaconInfoContent: MessageBeaconInfoContent,
highlight: Boolean,
attributes: AbsMessageItem.Attributes,
): VectorEpoxyModel<*>? {
// TODO handle location received and stopped states
return when {
isLiveRunning(liveLocationContent) -> buildStartLiveItem(highlight, attributes)
else -> null
isLiveRunning(beaconInfoContent) -> buildStartLiveItem(highlight, attributes)
else -> null
}
}
private fun isLiveRunning(liveLocationContent: LiveLocationBeaconContent): Boolean {
return liveLocationContent.isLive.orFalse() && liveLocationContent.hasTimedOut.not()
private fun isLiveRunning(beaconInfoContent: MessageBeaconInfoContent): Boolean {
// TODO when we will use aggregatedSummary, check if the live has timed out as well
return beaconInfoContent.isLive.orFalse()
}
private fun buildStartLiveItem(

View file

@ -98,8 +98,8 @@ import org.matrix.android.sdk.api.session.events.model.RelationType
import org.matrix.android.sdk.api.session.events.model.content.EncryptedEventContent
import org.matrix.android.sdk.api.session.events.model.isThread
import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.room.model.livelocation.LiveLocationBeaconContent
import org.matrix.android.sdk.api.session.room.model.message.MessageAudioContent
import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconInfoContent
import org.matrix.android.sdk.api.session.room.model.message.MessageContent
import org.matrix.android.sdk.api.session.room.model.message.MessageContentWithFormattedBody
import org.matrix.android.sdk.api.session.room.model.message.MessageEmoteContent
@ -207,15 +207,15 @@ class MessageItemFactory @Inject constructor(
is MessageAudioContent -> buildAudioContent(params, messageContent, informationData, highlight, attributes)
is MessageVerificationRequestContent -> buildVerificationRequestMessageItem(messageContent, informationData, highlight, callback, attributes)
is MessagePollContent -> buildPollItem(messageContent, informationData, highlight, callback, attributes)
is MessageLocationContent -> {
is MessageLocationContent -> {
if (vectorPreferences.labsRenderLocationsInTimeline()) {
buildLocationItem(messageContent, informationData, highlight, attributes)
} else {
buildMessageTextItem(messageContent.body, false, informationData, highlight, callback, attributes)
}
}
is LiveLocationBeaconContent -> liveLocationMessageItemFactory.create(messageContent, highlight, attributes)
else -> buildNotHandledMessageItem(messageContent, informationData, highlight, callback, attributes)
is MessageBeaconInfoContent -> liveLocationMessageItemFactory.create(messageContent, highlight, attributes)
else -> buildNotHandledMessageItem(messageContent, informationData, highlight, callback, attributes)
}
return messageItem?.apply {
layout(informationData.messageLayout.layoutRes)

View file

@ -59,12 +59,12 @@ class TimelineMessageLayoutFactory @Inject constructor(private val session: Sess
MessageType.MSGTYPE_VIDEO,
MessageType.MSGTYPE_STICKER_LOCAL,
MessageType.MSGTYPE_EMOTE,
MessageType.MSGTYPE_LIVE_LOCATION_STATE,
MessageType.MSGTYPE_BEACON_INFO,
)
private val MSG_TYPES_WITH_TIMESTAMP_INSIDE_MESSAGE = setOf(
MessageType.MSGTYPE_IMAGE,
MessageType.MSGTYPE_VIDEO,
MessageType.MSGTYPE_LIVE_LOCATION_STATE,
MessageType.MSGTYPE_BEACON_INFO,
)
}
@ -151,8 +151,8 @@ class TimelineMessageLayoutFactory @Inject constructor(private val session: Sess
private fun MessageContent?.shouldAddMessageOverlay(): Boolean {
return when {
this == null || msgType == MessageType.MSGTYPE_LIVE_LOCATION_STATE -> false
msgType == MessageType.MSGTYPE_LOCATION -> vectorPreferences.labsRenderLocationsInTimeline()
this == null || msgType == MessageType.MSGTYPE_BEACON_INFO -> false
msgType == MessageType.MSGTYPE_LOCATION -> vectorPreferences.labsRenderLocationsInTimeline()
else -> msgType in MSG_TYPES_WITH_TIMESTAMP_INSIDE_MESSAGE
}
}

View file

@ -32,7 +32,7 @@ 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.getRoom
import org.matrix.android.sdk.api.session.room.model.livelocation.LiveLocationBeaconContent
import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconInfoContent
import timber.log.Timber
import java.util.Timer
import java.util.TimerTask
@ -96,10 +96,10 @@ class LocationSharingService : VectorService(), LocationTracker.Callback {
}
private suspend fun sendLiveBeaconInfo(session: Session, roomArgs: RoomArgs) {
val beaconContent = LiveLocationBeaconContent(
val beaconContent = MessageBeaconInfoContent(
timeout = roomArgs.durationMillis,
isLive = true,
unstableTimestampAsMilliseconds = clock.epochMillis()
unstableTimestampMillis = clock.epochMillis()
).toContent()
val stateKey = session.myUserId