mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2025-02-10 09:00:41 +01:00
Send live location data.
This commit is contained in:
parent
ff34ed9eb2
commit
c26c9ff1cc
@ -49,7 +49,8 @@ object EventType {
|
|||||||
const val STATE_ROOM_JOIN_RULES = "m.room.join_rules"
|
const val STATE_ROOM_JOIN_RULES = "m.room.join_rules"
|
||||||
const val STATE_ROOM_GUEST_ACCESS = "m.room.guest_access"
|
const val STATE_ROOM_GUEST_ACCESS = "m.room.guest_access"
|
||||||
const val STATE_ROOM_POWER_LEVELS = "m.room.power_levels"
|
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"
|
const val STATE_SPACE_CHILD = "m.space.child"
|
||||||
|
|
||||||
@ -121,12 +122,4 @@ object EventType {
|
|||||||
type == CALL_REJECT ||
|
type == CALL_REJECT ||
|
||||||
type == CALL_REPLACES
|
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.
|
* 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,
|
@Json(name = "m.beacon_info") val beaconInfo: BeaconInfo? = null,
|
||||||
/**
|
/**
|
||||||
* Beacon creation timestamp.
|
* 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"
|
const val MSGTYPE_STICKER_LOCAL = "org.matrix.android.sdk.sticker"
|
||||||
|
|
||||||
// Fake message types for poll events to be able to inherit them from MessageContent
|
// 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_START = "org.matrix.android.sdk.poll.start"
|
||||||
const val MSGTYPE_POLL_RESPONSE = "org.matrix.android.sdk.poll.response"
|
const val MSGTYPE_POLL_RESPONSE = "org.matrix.android.sdk.poll.response"
|
||||||
|
|
||||||
const val MSGTYPE_CONFETTI = "nic.custom.confetti"
|
const val MSGTYPE_CONFETTI = "nic.custom.confetti"
|
||||||
const val MSGTYPE_SNOWFALL = "io.element.effect.snowfall"
|
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
|
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
|
* Remove this failed message from the timeline
|
||||||
* @param localEcho the unsent local echo
|
* @param localEcho the unsent local echo
|
||||||
|
@ -134,6 +134,12 @@ internal class DefaultSendService @AssistedInject constructor(
|
|||||||
.let { sendEvent(it) }
|
.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 {
|
override fun redactEvent(event: Event, reason: String?): Cancelable {
|
||||||
// TODO manage media/attachements?
|
// TODO manage media/attachements?
|
||||||
val redactionEcho = localEchoEventFactory.createRedactEvent(roomId, event.eventId!!, reason)
|
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.MessageFileContent
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageFormat
|
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.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.MessageLocationContent
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessagePollContent
|
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.MessagePollResponseContent
|
||||||
@ -242,6 +243,32 @@ internal class LocalEchoEventFactory @Inject constructor(
|
|||||||
return createMessageEvent(roomId, content)
|
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,
|
fun createReplaceTextOfReply(roomId: String,
|
||||||
eventReplaced: TimelineEvent,
|
eventReplaced: TimelineEvent,
|
||||||
originalEvent: TimelineEvent,
|
originalEvent: TimelineEvent,
|
||||||
|
@ -29,8 +29,9 @@ import im.vector.app.features.session.coroutineScope
|
|||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
import org.matrix.android.sdk.api.session.Session
|
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.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.BeaconInfo
|
||||||
import org.matrix.android.sdk.api.session.room.model.livelocation.LiveLocationBeaconContent
|
import org.matrix.android.sdk.api.session.room.model.livelocation.LiveLocationBeaconContent
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
@ -104,12 +105,11 @@ class LocationSharingService : VectorService(), LocationTracker.Callback {
|
|||||||
unstableTimestampAsMilliseconds = clock.epochMillis()
|
unstableTimestampAsMilliseconds = clock.epochMillis()
|
||||||
).toContent()
|
).toContent()
|
||||||
|
|
||||||
val eventType = generateBeaconInfoStateEventType(session.myUserId)
|
|
||||||
val stateKey = session.myUserId
|
val stateKey = session.myUserId
|
||||||
session
|
session
|
||||||
.getRoom(roomArgs.roomId)
|
.getRoom(roomArgs.roomId)
|
||||||
?.sendStateEvent(
|
?.sendStateEvent(
|
||||||
eventType = eventType,
|
eventType = EventType.STATE_ROOM_BEACON_INFO.first(),
|
||||||
stateKey = stateKey,
|
stateKey = stateKey,
|
||||||
body = beaconContent
|
body = beaconContent
|
||||||
)
|
)
|
||||||
@ -143,6 +143,17 @@ class LocationSharingService : VectorService(), LocationTracker.Callback {
|
|||||||
|
|
||||||
override fun onLocationUpdate(locationData: LocationData) {
|
override fun onLocationUpdate(locationData: LocationData) {
|
||||||
Timber.i("### LocationSharingService.onLocationUpdate. Uncertainty: ${locationData.uncertainty}")
|
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() {
|
override fun onLocationProviderIsNotAvailable() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user