mirror of
https://github.com/element-hq/element-android
synced 2024-11-27 20:06:51 +03:00
Send live location data.
This commit is contained in:
parent
ff34ed9eb2
commit
c26c9ff1cc
8 changed files with 115 additions and 14 deletions
|
@ -49,7 +49,8 @@ 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"
|
||||
private const val STATE_ROOM_BEACON_INFO_PREFIX = "org.matrix.msc3489.beacon_info."
|
||||
val STATE_ROOM_BEACON_INFO = listOf("org.matrix.msc3672.beacon_info", "m.beacon_info")
|
||||
val BEACON_LOCATION_DATA = listOf("org.matrix.msc3672.beacon", "m.beacon")
|
||||
|
||||
const val STATE_SPACE_CHILD = "m.space.child"
|
||||
|
||||
|
@ -121,12 +122,4 @@ 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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ data class LiveLocationBeaconContent(
|
|||
/**
|
||||
* Indicates user's intent to share ephemeral location.
|
||||
*/
|
||||
@Json(name = "org.matrix.msc3489.beacon_info") val unstableBeaconInfo: BeaconInfo? = null,
|
||||
@Json(name = "org.matrix.msc3672.beacon_info") val unstableBeaconInfo: BeaconInfo? = null,
|
||||
@Json(name = "m.beacon_info") val beaconInfo: BeaconInfo? = null,
|
||||
/**
|
||||
* Beacon creation timestamp.
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* 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.
|
||||
* 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.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.relation.RelationDefaultContent
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class MessageLiveLocationContent(
|
||||
/**
|
||||
* Local message type, not from server
|
||||
*/
|
||||
@Transient
|
||||
override val msgType: String = MessageType.MSGTYPE_LIVE_LOCATION,
|
||||
|
||||
@Json(name = "body") override val body: String = "",
|
||||
@Json(name = "m.relates_to") override val relatesTo: RelationDefaultContent? = null,
|
||||
@Json(name = "m.new_content") override val newContent: Content? = null,
|
||||
|
||||
/**
|
||||
* See [MSC3488](https://github.com/matrix-org/matrix-doc/blob/matthew/location/proposals/3488-location.md)
|
||||
*/
|
||||
@Json(name = "org.matrix.msc3488.location") val unstableLocationInfo: LocationInfo? = null,
|
||||
@Json(name = "m.location") val locationInfo: LocationInfo? = null,
|
||||
|
||||
/**
|
||||
* 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
|
||||
) : MessageContent {
|
||||
|
||||
fun getBestLocationInfo() = locationInfo ?: unstableLocationInfo
|
||||
|
||||
fun getBestTs() = ts ?: unstableTs
|
||||
}
|
|
@ -33,10 +33,13 @@ object MessageType {
|
|||
const val MSGTYPE_STICKER_LOCAL = "org.matrix.android.sdk.sticker"
|
||||
|
||||
// Fake message types for poll events to be able to inherit them from MessageContent
|
||||
// Because poll events are not message events and they don't hanve msgtype field
|
||||
// Because poll events are not message events and they don't have msgtype field
|
||||
const val MSGTYPE_POLL_START = "org.matrix.android.sdk.poll.start"
|
||||
const val MSGTYPE_POLL_RESPONSE = "org.matrix.android.sdk.poll.response"
|
||||
|
||||
const val MSGTYPE_CONFETTI = "nic.custom.confetti"
|
||||
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 = "org.matrix.android.sdk.livelocation"
|
||||
}
|
||||
|
|
|
@ -146,6 +146,15 @@ interface SendService {
|
|||
*/
|
||||
fun sendLocation(latitude: Double, longitude: Double, uncertainty: Double?, isUserLocation: Boolean): Cancelable
|
||||
|
||||
/**
|
||||
* Send a live location event to the room. beacon_info state event has to be sent before sending live location updates.
|
||||
* @param beaconInfoEventId event id of the initial beacon info state event
|
||||
* @param latitude required latitude of the location
|
||||
* @param longitude required longitude of the location
|
||||
* @param uncertainty Accuracy of the location in meters
|
||||
*/
|
||||
fun sendLiveLocation(beaconInfoEventId: String, latitude: Double, longitude: Double, uncertainty: Double?): Cancelable
|
||||
|
||||
/**
|
||||
* Remove this failed message from the timeline
|
||||
* @param localEcho the unsent local echo
|
||||
|
|
|
@ -134,6 +134,12 @@ internal class DefaultSendService @AssistedInject constructor(
|
|||
.let { sendEvent(it) }
|
||||
}
|
||||
|
||||
override fun sendLiveLocation(beaconInfoEventId: String, latitude: Double, longitude: Double, uncertainty: Double?): Cancelable {
|
||||
return localEchoEventFactory.createLiveLocationEvent(beaconInfoEventId, roomId, latitude, longitude, uncertainty)
|
||||
.also { createLocalEcho(it) }
|
||||
.let { sendEvent(it) }
|
||||
}
|
||||
|
||||
override fun redactEvent(event: Event, reason: String?): Cancelable {
|
||||
// TODO manage media/attachements?
|
||||
val redactionEcho = localEchoEventFactory.createRedactEvent(roomId, event.eventId!!, reason)
|
||||
|
|
|
@ -43,6 +43,7 @@ import org.matrix.android.sdk.api.session.room.model.message.MessageEndPollConte
|
|||
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
|
||||
|
@ -242,6 +243,32 @@ internal class LocalEchoEventFactory @Inject constructor(
|
|||
return createMessageEvent(roomId, content)
|
||||
}
|
||||
|
||||
fun createLiveLocationEvent(beaconInfoEventId: String,
|
||||
roomId: String,
|
||||
latitude: Double,
|
||||
longitude: Double,
|
||||
uncertainty: Double?): Event {
|
||||
val geoUri = buildGeoUri(latitude, longitude, uncertainty)
|
||||
val content = MessageLiveLocationContent(
|
||||
body = geoUri,
|
||||
relatesTo = RelationDefaultContent(
|
||||
type = RelationType.REFERENCE,
|
||||
eventId = beaconInfoEventId
|
||||
),
|
||||
unstableLocationInfo = LocationInfo(geoUri = geoUri, description = geoUri),
|
||||
unstableTs = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()),
|
||||
)
|
||||
val localId = LocalEcho.createLocalEchoId()
|
||||
return Event(
|
||||
roomId = roomId,
|
||||
originServerTs = dummyOriginServerTs(),
|
||||
senderId = userId,
|
||||
eventId = localId,
|
||||
type = EventType.BEACON_LOCATION_DATA.first(),
|
||||
content = content.toContent(),
|
||||
unsignedData = UnsignedData(age = null, transactionId = localId))
|
||||
}
|
||||
|
||||
fun createReplaceTextOfReply(roomId: String,
|
||||
eventReplaced: TimelineEvent,
|
||||
originalEvent: TimelineEvent,
|
||||
|
|
|
@ -29,8 +29,9 @@ 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.generateBeaconInfoStateEventType
|
||||
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.Room
|
||||
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
|
||||
|
@ -104,12 +105,11 @@ class LocationSharingService : VectorService(), LocationTracker.Callback {
|
|||
unstableTimestampAsMilliseconds = clock.epochMillis()
|
||||
).toContent()
|
||||
|
||||
val eventType = generateBeaconInfoStateEventType(session.myUserId)
|
||||
val stateKey = session.myUserId
|
||||
session
|
||||
.getRoom(roomArgs.roomId)
|
||||
?.sendStateEvent(
|
||||
eventType = eventType,
|
||||
eventType = EventType.STATE_ROOM_BEACON_INFO.first(),
|
||||
stateKey = stateKey,
|
||||
body = beaconContent
|
||||
)
|
||||
|
@ -143,6 +143,17 @@ class LocationSharingService : VectorService(), LocationTracker.Callback {
|
|||
|
||||
override fun onLocationUpdate(locationData: LocationData) {
|
||||
Timber.i("### LocationSharingService.onLocationUpdate. Uncertainty: ${locationData.uncertainty}")
|
||||
roomArgsList.forEach { roomArg ->
|
||||
val room = activeSessionHolder.getSafeActiveSession()?.getRoom(roomArg.roomId)
|
||||
room?.getStateEvent(EventType.STATE_ROOM_BEACON_INFO.first())?.let { beaconInfoEvent ->
|
||||
room.sendLiveLocation(
|
||||
beaconInfoEventId = beaconInfoEvent.eventId!!,
|
||||
latitude = locationData.latitude,
|
||||
longitude = locationData.longitude,
|
||||
uncertainty = locationData.uncertainty
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onLocationProviderIsNotAvailable() {
|
||||
|
|
Loading…
Reference in a new issue