Merge pull request #6500 from osmandapp/TelegramDataBase

Telegram improvements
This commit is contained in:
Alexey 2019-02-01 14:38:19 +03:00 committed by GitHub
commit 5daac573a1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 300 additions and 131 deletions

View file

@ -277,7 +277,9 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
override fun onReceiveChatLocationMessages(chatId: Long, vararg messages: TdApi.Message) {
app().showLocationHelper.startShowMessagesTask(chatId, *messages)
messages.forEach {
app().locationMessages.addNewLocationMessage(it)
if (!it.isOutgoing) {
app().locationMessages.addNewLocationMessage(it)
}
}
}
@ -294,7 +296,9 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
app().settings.updateShareInfo(it)
app().shareLocationHelper.checkAndSendBufferMessagesToChat(it.chatId)
if (it.sendingState == null && (it.content is TdApi.MessageLocation || it.content is TdApi.MessageText)) {
app().locationMessages.addNewLocationMessage(it)
if (!it.isOutgoing) {
app().locationMessages.addNewLocationMessage(it)
}
}
}
}

View file

@ -360,7 +360,7 @@ class TelegramSettings(private val app: TelegramApplication) {
if (lm.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
val loc = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER)
val gpsActive = loc != null && ((statusChangeTime - loc.time) / 1000) < GPS_UPDATE_EXPIRED_TIME
val lastSentLocationExpired = ((statusChangeTime - app.shareLocationHelper.lastLocationMessageSentTime) / 1000) > GPS_UPDATE_EXPIRED_TIME
val lastSentLocationExpired = ((statusChangeTime - app.shareLocationHelper.lastLocationUpdateTime) / 1000) > GPS_UPDATE_EXPIRED_TIME
(gpsActive || !lastSentLocationExpired)
} else {
false
@ -393,7 +393,7 @@ class TelegramSettings(private val app: TelegramApplication) {
} else if (!initializing) {
when {
!gpsEnabled -> {
locationTime = app.shareLocationHelper.lastLocationMessageSentTime
locationTime = app.shareLocationHelper.lastLocationUpdateTime
if (locationTime <= 0) {
locationTime = getLastSuccessfulSendTime()
}

View file

@ -4,19 +4,21 @@ import android.content.Context
import android.database.Cursor
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import net.osmand.Location
import net.osmand.PlatformUtil
import net.osmand.data.LatLon
import net.osmand.telegram.TelegramApplication
import net.osmand.telegram.utils.OsmandLocationUtils
import net.osmand.util.MapUtils
import org.drinkless.td.libcore.telegram.TdApi
class LocationMessages(val app: TelegramApplication) {
private val log = PlatformUtil.getLog(LocationMessages::class.java)
// todo - bufferedMessages is for prepared/pending messages only. On app start we read prepared/pending messages to bufferedMessages. After status changed to sent/error - remove message from buffered.
private var bufferedMessages = emptyList<BufferMessage>()
private var lastMessages = emptyList<LocationMessage>()
private var lastLocationPoints = mutableMapOf<LocationHistoryPoint, LatLon>()
private val dbHelper: SQLiteHelper
@ -33,11 +35,14 @@ class LocationMessages(val app: TelegramApplication) {
return bufferedMessages.filter { it.chatId==chatId }.sortedBy { it.time }
}
// todo - read from db by date (Victor's suggestion - filter by one day only. Need to be changed in UI also.
fun getIngoingMessages(currentUserId: Int, start: Long, end: Long): List<LocationMessage> {
return dbHelper.getIngoingMessages(currentUserId, start, end)
}
fun getIngoingUserLocations(currentUserId: Int, start: Long, end: Long): List<UserLocations> {
return dbHelper.getIngoingUserLocations(currentUserId, start, end)
}
fun getMessagesForUserInChat(userId: Int, chatId: Long, start: Long, end: Long): List<LocationMessage> {
return dbHelper.getMessagesForUserInChat(userId, chatId, start, end)
}
@ -46,6 +51,10 @@ class LocationMessages(val app: TelegramApplication) {
return dbHelper.getMessagesForUser(userId, start, end)
}
fun getUserLocations(userId: Int, start: Long, end: Long): UserLocations? {
return dbHelper.getUserLocations(userId, start, end)
}
fun addBufferedMessage(message: BufferMessage) {
log.debug("addBufferedMessage $message")
val messages = mutableListOf(*this.bufferedMessages.toTypedArray())
@ -58,17 +67,28 @@ class LocationMessages(val app: TelegramApplication) {
log.debug("addNewLocationMessage ${message.id}")
val type = OsmandLocationUtils.getMessageType(message, app.telegramHelper)
val previousMessage = lastMessages.firstOrNull { it.chatId == message.chatId && it.userId == message.senderUserId && it.type == type }
val locationMessage = OsmandLocationUtils.parseMessage(message, app.telegramHelper, previousMessage)
val newItem = LocationHistoryPoint(message.senderUserId, message.chatId, type)
val previousMessageLatLon = lastLocationPoints[newItem]
val locationMessage = OsmandLocationUtils.parseMessage(message, app.telegramHelper, previousMessageLatLon)
if (locationMessage != null) {
dbHelper.addLocationMessage(locationMessage)
val messages = mutableListOf(*this.lastMessages.toTypedArray())
messages.remove(previousMessage)
messages.add(locationMessage)
this.lastMessages = messages
lastLocationPoints[newItem] = LatLon(locationMessage.lat, locationMessage.lon)
}
}
fun addMyLocationMessage(loc: Location) {
log.debug("addMyLocationMessage")
val currentUserId = app.telegramHelper.getCurrentUserId()
val newItem = LocationHistoryPoint(currentUserId, 0, -1)
val previousMessageLatLon = lastLocationPoints[newItem]
val distance = if (previousMessageLatLon != null) { MapUtils.getDistance(previousMessageLatLon, loc.latitude, loc.longitude) } else 0.0
val message = LocationMessages.LocationMessage(currentUserId, 0, loc.latitude, loc.longitude, loc.altitude,
loc.speed.toDouble(), loc.accuracy.toDouble(), loc.bearing.toDouble(), loc.time, -1, 0, distance)
dbHelper.addLocationMessage(message)
lastLocationPoints[newItem] = LatLon(message.lat, message.lon)
}
fun clearBufferedMessages() {
log.debug("clearBufferedMessages")
dbHelper.clearBufferedMessages()
@ -88,7 +108,7 @@ class LocationMessages(val app: TelegramApplication) {
}
private fun readLastMessages() {
this.lastMessages = dbHelper.getLastMessages()
this.lastLocationPoints = dbHelper.getLastMessages()
}
private class SQLiteHelper(context: Context) :
@ -121,7 +141,7 @@ class LocationMessages(val app: TelegramApplication) {
internal fun getMessagesForUser(userId: Int, start: Long, end: Long): List<LocationMessage> {
val res = arrayListOf<LocationMessage>()
readableDatabase?.rawQuery(
"$TIMELINE_TABLE_SELECT WHERE $COL_USER_ID = ? AND $COL_TIME BETWEEN $start AND $end ORDER BY $COL_TIME ASC ",
"$TIMELINE_TABLE_SELECT WHERE $COL_USER_ID = ? AND $COL_TIME BETWEEN $start AND $end ORDER BY $COL_CHAT_ID ASC, $COL_TYPE DESC, $COL_TIME ASC ",
arrayOf(userId.toString()))?.apply {
if (moveToFirst()) {
do {
@ -133,6 +153,33 @@ class LocationMessages(val app: TelegramApplication) {
return res
}
internal fun getUserLocations(userId: Int, start: Long, end: Long): UserLocations? {
var userLocations: UserLocations? = null
readableDatabase?.rawQuery(
"$TIMELINE_TABLE_SELECT WHERE $COL_USER_ID = ? AND $COL_TIME BETWEEN $start AND $end ORDER BY $COL_CHAT_ID ASC, $COL_TYPE DESC, $COL_TIME ASC ",
arrayOf(userId.toString()))?.apply {
var type = -1
val userLocationsMap: MutableMap<Int, List<LocationMessage>> = mutableMapOf()
userLocations = UserLocations(userId, 0, emptyMap())
var userLocationsListBytetype: MutableList<LocationMessage>? = null
if (moveToFirst()) {
do {
val locationMessage = readLocationMessage(this@apply)
if (type != locationMessage.type) {
type = locationMessage.type
userLocationsListBytetype = mutableListOf()
userLocationsListBytetype.add(locationMessage)
userLocationsMap.set(type, userLocationsListBytetype)
} else {
userLocationsListBytetype?.add(locationMessage)
}
} while (moveToNext())
}
close()
}
return userLocations
}
internal fun getPreviousMessage(userId: Int, chatId: Long): LocationMessage? {
var res:LocationMessage? = null
readableDatabase?.rawQuery(
@ -149,7 +196,7 @@ class LocationMessages(val app: TelegramApplication) {
internal fun getIngoingMessages(currentUserId: Int, start: Long, end: Long): List<LocationMessage> {
val res = arrayListOf<LocationMessage>()
readableDatabase?.rawQuery(
"$TIMELINE_TABLE_SELECT WHERE $COL_USER_ID != ? AND $COL_TIME BETWEEN $start AND $end ORDER BY $COL_USER_ID ASC, $COL_CHAT_ID ASC, $COL_TIME ASC ",
"$TIMELINE_TABLE_SELECT WHERE $COL_USER_ID != ? AND $COL_TIME BETWEEN $start AND $end ORDER BY $COL_USER_ID, $COL_CHAT_ID, $COL_TYPE DESC, $COL_TIME ",
arrayOf(currentUserId.toString()))?.apply {
if (moveToFirst()) {
do {
@ -161,10 +208,50 @@ class LocationMessages(val app: TelegramApplication) {
return res
}
internal fun getIngoingUserLocations(currentUserId: Int, start: Long, end: Long): List<UserLocations> {
val res = arrayListOf<UserLocations>()
readableDatabase?.rawQuery(
"$TIMELINE_TABLE_SELECT WHERE $COL_USER_ID != ? AND $COL_TIME BETWEEN $start AND $end ORDER BY $COL_USER_ID, $COL_CHAT_ID, $COL_TYPE DESC, $COL_TIME ",
arrayOf(currentUserId.toString()))?.apply {
var type = -1
var userId = -1
var chatId = -1L
var userLocations: UserLocations? = null
var userLocationsMap: MutableMap<Int, List<LocationMessage>>? = null
var userLocationsListBytetype: MutableList<LocationMessage>? = null
if (moveToFirst()) {
do {
val locationMessage = readLocationMessage(this@apply)
if (userId != locationMessage.userId || chatId != locationMessage.chatId) {
userId = locationMessage.userId
chatId = locationMessage.chatId
type = locationMessage.type
userLocationsMap = mutableMapOf()
userLocationsListBytetype = mutableListOf()
userLocationsListBytetype.add(locationMessage)
userLocationsMap[type] = userLocationsListBytetype
userLocations = UserLocations(userId, chatId, userLocationsMap)
res.add(userLocations)
}
if (type != locationMessage.type) {
type = locationMessage.type
userLocationsListBytetype = mutableListOf()
userLocationsListBytetype.add(locationMessage)
userLocationsMap?.set(type, userLocationsListBytetype)
} else {
userLocationsListBytetype?.add(locationMessage)
}
} while (moveToNext())
}
close()
}
return res
}
internal fun getMessagesForUserInChat(userId: Int, chatId: Long, start: Long, end: Long): List<LocationMessage> {
val res = arrayListOf<LocationMessage>()
readableDatabase?.rawQuery(
"$TIMELINE_TABLE_SELECT WHERE $COL_USER_ID = ? AND $COL_CHAT_ID = ? AND $COL_TIME BETWEEN $start AND $end ORDER BY $COL_TIME ASC ",
"$TIMELINE_TABLE_SELECT WHERE $COL_USER_ID = ? AND $COL_CHAT_ID = ? AND $COL_TIME BETWEEN $start AND $end ORDER BY $COL_TYPE DESC, $COL_TIME ",
arrayOf(userId.toString(), chatId.toString()))?.apply {
if (moveToFirst()) {
do {
@ -189,12 +276,12 @@ class LocationMessages(val app: TelegramApplication) {
return res
}
internal fun getLastMessages(): List<LocationMessage> {
val res = arrayListOf<LocationMessage>()
readableDatabase?.rawQuery(TIMELINE_TABLE_SELECT, null)?.apply {
internal fun getLastMessages(): MutableMap<LocationHistoryPoint, LatLon> {
val res = mutableMapOf<LocationHistoryPoint, LatLon>()
readableDatabase?.rawQuery("$TIMELINE_TABLE_SELECT_HISTORY_POINTS ORDER BY $COL_TIME ASC", null)?.apply {
if (moveToFirst()) {
do {
res.add(readLocationMessage(this@apply))
// res.add(readLocationMessage(this@apply))
} while (moveToNext())
}
close()
@ -233,6 +320,16 @@ class LocationMessages(val app: TelegramApplication) {
return BufferMessage(chatId, lat, lon, altitude, speed, hdop, bearing, date, type)
}
internal fun readLocationHistoryPoint(cursor: Cursor): Pair<LocationHistoryPoint, LatLon> {
val userId = cursor.getInt(0)
val chatId = cursor.getLong(1)
val lat = cursor.getDouble(2)
val lon = cursor.getDouble(3)
val type = cursor.getInt(4)
return Pair(LocationHistoryPoint(userId, chatId, type), LatLon(lat, lon))
}
internal fun clearBufferedMessages() {
writableDatabase?.execSQL(BUFFER_TABLE_CLEAR)
}
@ -288,6 +385,9 @@ class LocationMessages(val app: TelegramApplication) {
private const val TIMELINE_TABLE_SELECT =
"SELECT $COL_USER_ID, $COL_CHAT_ID, $COL_LAT, $COL_LON, $COL_ALTITUDE, $COL_SPEED, $COL_HDOP, $COL_BEARING, $COL_TIME, $COL_TYPE, $COL_MESSAGE_ID, $COL_DISTANCE_FROM_PREV FROM $TIMELINE_TABLE_NAME"
private const val TIMELINE_TABLE_SELECT_HISTORY_POINTS =
"SELECT $COL_USER_ID, $COL_CHAT_ID, $COL_LAT, $COL_LON, $COL_TIME, $COL_TYPE FROM $TIMELINE_TABLE_NAME"
private const val TIMELINE_TABLE_CLEAR = "DELETE FROM $TIMELINE_TABLE_NAME"
private const val TIMELINE_TABLE_DELETE = "DROP TABLE IF EXISTS $TIMELINE_TABLE_NAME"
@ -335,6 +435,40 @@ class LocationMessages(val app: TelegramApplication) {
val time: Long,
val type: Int)
data class UserLocations(
var userId: Int,
var chatId: Long,
var locationsByType: Map<Int, List<LocationMessage>>
)
data class LocationHistoryPoint(
val userId: Int,
val chatId: Long,
val type: Int
) {
override fun equals(other: Any?): Boolean {
if (other == null) {
return false
}
if (other !is LocationHistoryPoint) {
return false
}
val o = other as LocationHistoryPoint?
return this.userId == o!!.userId && this.chatId == o.chatId && this.type == o.type
}
override fun hashCode(): Int {
val prime = 31
var result = 1
result = prime * result + userId.hashCode()
result = prime * result + chatId.hashCode()
result = prime * result + type.hashCode()
return result
}
}
companion object {
const val TYPE_USER_MAP = 0

View file

@ -203,6 +203,15 @@ class OsmandAidlHelper(private val app: TelegramApplication) {
}
}
fun execOsmandApi(action: (() -> Unit)) {
if (!isOsmandConnected() && isOsmandBound()) {
connectOsmand()
}
if (isOsmandConnected()) {
action.invoke()
}
}
private fun bindService(packageName: String): Boolean {
return if (mIOsmAndAidlInterface == null) {
val intent = Intent("net.osmand.aidl.OsmandAidlService")

View file

@ -13,6 +13,8 @@ import org.json.JSONObject
private const val USER_SET_LIVE_PERIOD_DELAY_MS = 5000 // 5 sec
private const val MY_LOCATION_UPDATE_MS = 15000 // 15 sec
class ShareLocationHelper(private val app: TelegramApplication) {
private val log = PlatformUtil.getLog(ShareLocationHelper::class.java)
@ -26,7 +28,7 @@ class ShareLocationHelper(private val app: TelegramApplication) {
var distance: Int = 0
private set
var lastLocationMessageSentTime: Long = 0
var lastLocationUpdateTime: Long = 0
var lastLocation: Location? = null
set(value) {
@ -52,7 +54,7 @@ class ShareLocationHelper(private val app: TelegramApplication) {
if (app.settings.getChatsShareInfo().isNotEmpty()) {
shareLocationMessages(location, app.telegramHelper.getCurrentUserId())
}
lastLocationMessageSentTime = System.currentTimeMillis()
lastLocationUpdateTime = System.currentTimeMillis()
}
app.settings.updateSharingStatusHistory()
refreshNotification()
@ -188,6 +190,11 @@ class ShareLocationHelper(private val app: TelegramApplication) {
val chatsShareInfo = app.settings.getChatsShareInfo()
val latitude = location.latitude
val longitude = location.longitude
val altitude = location.altitude
val speed = location.speed.toDouble()
val accuracy = location.accuracy.toDouble()
val bearing = location.bearing.toDouble()
val time = location.time
val sharingMode = app.settings.currentSharingMode
val isBot = sharingMode != userId.toString()
var bufferedMessagesFull = false
@ -206,10 +213,7 @@ class ShareLocationHelper(private val app: TelegramApplication) {
if (shareInfo.pendingTdLib >= 10) {
bufferedMessagesFull = true
}
val message = BufferMessage(
shareInfo.chatId, latitude, longitude, location.altitude, location.speed.toDouble(),
location.accuracy.toDouble(), location.bearing.toDouble(), System.currentTimeMillis(), type
)
val message = BufferMessage(shareInfo.chatId, latitude, longitude, altitude, speed, accuracy, bearing, time, type)
if (type == LocationMessages.TYPE_USER_MAP || type == LocationMessages.TYPE_BOT_MAP) {
prepareMapMessage(shareInfo, message, isBot, sharingMode)
@ -219,6 +223,9 @@ class ShareLocationHelper(private val app: TelegramApplication) {
prepareMapAndTextMessage(shareInfo, message, isBot, sharingMode)
}
}
if (System.currentTimeMillis() - lastLocationUpdateTime > MY_LOCATION_UPDATE_MS) {
app.locationMessages.addMyLocationMessage(location)
}
if (bufferedMessagesFull) {
checkNetworkType()
}
@ -226,9 +233,9 @@ class ShareLocationHelper(private val app: TelegramApplication) {
private fun prepareTextMessage(shareInfo: TelegramSettings.ShareChatInfo,message: BufferMessage,isBot:Boolean, sharingMode: String) {
log.debug("prepareTextMessage $message")
shareInfo.collectedMessages++
if (shareInfo.currentTextMessageId == -1L) {
if (shareInfo.pendingTextMessage) {
shareInfo.collectedMessages++
app.locationMessages.addBufferedMessage(message)
} else {
if (isBot) {
@ -244,6 +251,7 @@ class ShareLocationHelper(private val app: TelegramApplication) {
if (shareInfo.pendingTdLib < 10) {
app.telegramHelper.editTextLocation(shareInfo, message)
} else {
shareInfo.collectedMessages++
app.locationMessages.addBufferedMessage(message)
}
}
@ -252,9 +260,9 @@ class ShareLocationHelper(private val app: TelegramApplication) {
private fun prepareMapMessage(shareInfo: TelegramSettings.ShareChatInfo,message: BufferMessage,isBot:Boolean, sharingMode: String) {
log.debug("prepareMapMessage $message")
shareInfo.collectedMessages++
if (shareInfo.currentMapMessageId == -1L) {
if (shareInfo.pendingMapMessage) {
shareInfo.collectedMessages++
app.locationMessages.addBufferedMessage(message)
} else {
if (isBot) {
@ -279,8 +287,8 @@ class ShareLocationHelper(private val app: TelegramApplication) {
private fun prepareMapAndTextMessage(shareInfo: TelegramSettings.ShareChatInfo, message: BufferMessage, isBot:Boolean, sharingMode: String) {
log.debug("prepareMapAndTextMessage $message")
shareInfo.collectedMessages++
if (shareInfo.pendingMapMessage || shareInfo.pendingTextMessage || shareInfo.pendingTdLib >= 10) {
shareInfo.collectedMessages++
app.locationMessages.addBufferedMessage(message)
} else {
if (isBot) {

View file

@ -35,7 +35,7 @@ class ShowLocationHelper(private val app: TelegramApplication) {
private var forcedStop: Boolean = false
fun setupMapLayer() {
execOsmandApi {
osmandAidlHelper.execOsmandApi {
osmandAidlHelper.addMapLayer(MAP_LAYER_ID, "Telegram", 5.5f, null)
}
}
@ -44,7 +44,7 @@ class ShowLocationHelper(private val app: TelegramApplication) {
if (item.latLon == null) {
return
}
execOsmandApi {
osmandAidlHelper.execOsmandApi {
osmandAidlHelper.showMapPoint(
MAP_LAYER_ID,
item.getMapPointId(),
@ -60,7 +60,7 @@ class ShowLocationHelper(private val app: TelegramApplication) {
}
fun updateLocationsOnMap() {
execOsmandApi {
osmandAidlHelper.execOsmandApi {
val messages = telegramHelper.getMessages()
for (message in messages) {
val date = OsmandLocationUtils.getLastUpdatedTime(message)
@ -75,7 +75,7 @@ class ShowLocationHelper(private val app: TelegramApplication) {
}
fun addOrUpdateLocationOnMap(message: TdApi.Message, update: Boolean = false) {
execOsmandApi {
osmandAidlHelper.execOsmandApi {
val chatId = message.chatId
val chatTitle = telegramHelper.getChat(message.chatId)?.title
val content = message.content
@ -133,7 +133,7 @@ class ShowLocationHelper(private val app: TelegramApplication) {
}
fun showChatMessages(chatId: Long) {
execOsmandApi {
osmandAidlHelper.execOsmandApi {
val messages = telegramHelper.getChatMessages(chatId)
for (message in messages) {
addOrUpdateLocationOnMap(message)
@ -146,7 +146,7 @@ class ShowLocationHelper(private val app: TelegramApplication) {
}
fun hideMessages(messages: List<TdApi.Message>) {
execOsmandApi {
osmandAidlHelper.execOsmandApi {
for (message in messages) {
val user = telegramHelper.getUser(message.senderUserId)
if (user != null) {
@ -257,13 +257,4 @@ class ShowLocationHelper(private val app: TelegramApplication) {
osmandAidlHelper.removeMapPoint(MAP_LAYER_ID, "${chatId}_${content.name}")
}
}
private fun execOsmandApi(action: (() -> Unit)) {
if (!osmandAidlHelper.isOsmandConnected() && osmandAidlHelper.isOsmandBound()) {
osmandAidlHelper.connectOsmand()
}
if (osmandAidlHelper.isOsmandConnected()) {
action.invoke()
}
}
}

View file

@ -1309,6 +1309,24 @@ class TelegramHelper private constructor() {
}
}
}
TdApi.UpdateMessageEdited.CONSTRUCTOR -> {
val updateMessageEdited = obj as TdApi.UpdateMessageEdited
val message = usersLocationMessages[updateMessageEdited.messageId]
log.debug("UpdateMessageEdited " + updateMessageEdited.messageId)
if (message == null) {
updateMessageEdited.apply {
requestMessage(chatId, messageId, this@TelegramHelper::addNewMessage)
}
} else {
synchronized(message) {
message.editDate = updateMessageEdited.editDate
lastTelegramUpdateTime = Math.max(message.date, message.editDate)
}
incomingMessagesListeners.forEach {
it.updateLocationMessages()
}
}
}
TdApi.UpdateMessageContent.CONSTRUCTOR -> {
val updateMessageContent = obj as TdApi.UpdateMessageContent
val message = usersLocationMessages[updateMessageContent.messageId]
@ -1325,9 +1343,12 @@ class TelegramHelper private constructor() {
val viaBot = isOsmAndBot(message.viaBotUserId)
message.content = if (newContent is TdApi.MessageText) {
parseTextLocation(newContent.text, (fromBot || viaBot))
} else if (newContent is TdApi.MessageLocation &&
(isOsmAndBot(message.senderUserId) || isOsmAndBot(message.viaBotUserId))) {
parseOsmAndBotLocationContent(message.content as MessageOsmAndBotLocation, newContent)
} else if (newContent is TdApi.MessageLocation) {
if(fromBot||viaBot){
parseOsmAndBotLocationContent(message.content as MessageOsmAndBotLocation, newContent)
} else {
OsmandLocationUtils.parseUserMapLocation(message)
}
} else {
newContent
}

View file

@ -131,10 +131,6 @@ object TelegramUiHelper {
}
}
fun gpxToChatItem(helper: TelegramHelper, gpx: GPXFile, simpleUserItem: Boolean): GpxChatItem? {
return if (simpleUserItem) gpxToUserGpxChatItem(helper, gpx) else gpxToGpxChatItem(helper, gpx)
}
private fun botMessageToLocationItem(
chat: TdApi.Chat,
content: MessageOsmAndBotLocation
@ -256,47 +252,31 @@ object TelegramUiHelper {
}
}
fun locationMessagesToChatItem(
helper: TelegramHelper,
messages: List<LocationMessages.LocationMessage>
): LocationMessagesChatItem? {
val message = messages.firstOrNull()
val user = helper.getUser(message?.userId ?: -1) ?: return null
val chat = helper.getChat(message?.chatId ?: -1) ?: return null
fun userLocationsToChatItem(helper: TelegramHelper, userLocation: LocationMessages.UserLocations): LocationMessagesChatItem? {
val user = helper.getUser(userLocation.userId)
val chat = helper.getChat(userLocation.chatId)
return LocationMessagesChatItem().apply {
chatId = chat.id
chatTitle = chat.title
locationMessages = messages
name = TelegramUiHelper.getUserName(user)
if (helper.isGroup(chat)) {
photoPath = helper.getUserPhotoPath(user)
groupPhotoPath = chat.photo?.small?.local?.path
if (chat != null) {
chatId = chat.id
chatTitle = chat.title
if (helper.isGroup(chat)) {
photoPath = helper.getUserPhotoPath(user)
groupPhotoPath = chat.photo?.small?.local?.path
} else {
photoPath = user?.profilePhoto?.small?.local?.path
privateChat = helper.isPrivateChat(chat) || helper.isSecretChat(chat)
}
} else {
photoPath = user.profilePhoto?.small?.local?.path
photoPath = user?.profilePhoto?.small?.local?.path
}
if (user != null) {
name = TelegramUiHelper.getUserName(user)
userId = user.id
}
userLocations = userLocation
grayscalePhotoPath = helper.getUserGreyPhotoPath(user)
placeholderId = R.drawable.img_user_picture
userId = user.id
privateChat = helper.isPrivateChat(chat) || helper.isSecretChat(chat)
chatWithBot = helper.isBot(userId)
lastUpdated = (messages.maxBy { it.time }?.time ?: -1).toInt()
}
}
private fun gpxToUserGpxChatItem(
helper: TelegramHelper,
gpx: GPXFile
): GpxChatItem? {
val user = helper.getUser(gpx.userId) ?: return null
return GpxChatItem().apply {
gpxFile = gpx
name = TelegramUiHelper.getUserName(user)
photoPath = user.profilePhoto?.small?.local?.path
grayscalePhotoPath = helper.getUserGreyPhotoPath(user)
placeholderId = R.drawable.img_user_picture
userId = user.id
chatWithBot = helper.isBot(userId)
lastUpdated = (gpx.modifiedTime / 1000).toInt()
}
}
@ -368,7 +348,7 @@ object TelegramUiHelper {
class LocationMessagesChatItem : ListItem() {
var locationMessages: List<LocationMessages.LocationMessage> = emptyList()
var userLocations: LocationMessages.UserLocations? = null
internal set
var groupPhotoPath: String? = null
internal set

View file

@ -19,8 +19,6 @@ import android.widget.*
import net.osmand.PlatformUtil
import net.osmand.telegram.R
import net.osmand.telegram.TelegramApplication
import net.osmand.telegram.helpers.LocationMessages
import net.osmand.telegram.helpers.LocationMessages.LocationMessage
import net.osmand.telegram.helpers.OsmandAidlHelper
import net.osmand.telegram.helpers.TelegramHelper
import net.osmand.telegram.helpers.TelegramHelper.*
@ -294,7 +292,9 @@ class MainActivity : AppCompatActivity(), TelegramListener, ActionButtonsListene
}
if (app.telegramService == null) {
messages.forEach {
if (!it.isOutgoing) {
app.locationMessages.addNewLocationMessage(it)
}
}
}
}

View file

@ -718,8 +718,7 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
}
holder.gpsPointsCollected?.apply {
if (shareInfo != null) {
val bufferedMessages = shareInfo.pendingTdLib + app.locationMessages.getBufferedMessagesForChat(shareInfo.chatId).size
text = "$bufferedMessages"
text = "${shareInfo.pendingTdLib + shareInfo.collectedMessages}"
}
}
holder.gpsPointsSent?.apply {

View file

@ -159,18 +159,18 @@ class TimelineTabFragment : Fragment() {
val res = mutableListOf<ListItem>()
val currentUserId = telegramHelper.getCurrentUser()?.id
if (currentUserId != null) {
val outgoingMessages = app.locationMessages.getMessagesForUser(currentUserId, start, end)
TelegramUiHelper.locationMessagesToChatItem(telegramHelper, outgoingMessages)?.also { chatItem ->
res.add(chatItem)
}
val ingoingMessages = app.locationMessages.getIngoingMessages(currentUserId, start, end)
val emm = ingoingMessages.distinctBy { Pair(it.userId, it.chatId) }
emm.forEach { message ->
TelegramUiHelper.locationMessagesToChatItem(telegramHelper,
ingoingMessages.filter { it.chatId == message.chatId && it.userId == message.userId })?.also { chatItem ->
val currentUserLocations = app.locationMessages.getUserLocations(currentUserId, start, end)
if (currentUserLocations != null) {
TelegramUiHelper.userLocationsToChatItem(telegramHelper, currentUserLocations)?.also { chatItem ->
res.add(chatItem)
}
}
val ingoingUserLocations = app.locationMessages.getIngoingUserLocations(currentUserId, start, end)
ingoingUserLocations.forEach {
TelegramUiHelper.userLocationsToChatItem(telegramHelper, it)?.also { chatItem ->
res.add(chatItem)
}
}
}
adapter.items = sortAdapterItems(res)
@ -205,17 +205,21 @@ class TimelineTabFragment : Fragment() {
val lastItem = position == itemCount - 1
val item = items[position]
val currentUserId = telegramHelper.getCurrentUser()?.id ?: 0
TelegramUiHelper.setupPhoto(app, holder.icon, item.photoPath, R.drawable.img_user_picture_active, false)
holder.title?.text = item.name
holder.bottomShadow?.visibility = if (lastItem) View.VISIBLE else View.GONE
holder.lastTelegramUpdateTime?.visibility = View.GONE
if (item is TelegramUiHelper.LocationMessagesChatItem) {
val distance = OsmandFormatter.getFormattedDistance(getDistance(item.locationMessages),app)
val name = if ((!item.privateChat || item.chatWithBot) && item.userId != currentUserId) item.getVisibleName() else ""
holder.groupDescrContainer?.visibility = View.VISIBLE
holder.groupTitle?.text = "$distance (${getString(R.string.points_size, item.locationMessages.size)}) $name"
if (item is TelegramUiHelper.LocationMessagesChatItem ) {
val userLocations = item.userLocations
if(userLocations!=null){
val pair = getDistanceAndCountedPoints(userLocations)
val distance = OsmandFormatter.getFormattedDistance(pair.first,app)
val name = if ((!item.privateChat || item.chatWithBot) && item.userId != currentUserId) item.getVisibleName() else ""
holder.groupDescrContainer?.visibility = View.VISIBLE
holder.groupTitle?.text = "$distance (${getString(R.string.points_size, pair.second)}) $name"
}
TelegramUiHelper.setupPhoto(app, holder.groupImage, item.groupPhotoPath, item.placeholderId, false)
holder.userRow?.setOnClickListener {
childFragmentManager.also {
@ -229,12 +233,27 @@ class TimelineTabFragment : Fragment() {
}
}
private fun getDistance(messages: List<LocationMessages.LocationMessage>): Float {
private fun getDistanceAndCountedPoints(userLocations: LocationMessages.UserLocations): Pair<Float, Int> {
val textUserLoc = userLocations.locationsByType[LocationMessages.TYPE_USER_TEXT]
val textBotLoc = userLocations.locationsByType[LocationMessages.TYPE_BOT_TEXT]
var dist = 0.0
messages.forEach {
dist += it.distanceFromPrev
var countedPoints = 0
when {
textUserLoc != null -> textUserLoc.forEach {
dist += it.distanceFromPrev
countedPoints++
}
textBotLoc != null -> textBotLoc.forEach {
dist += it.distanceFromPrev
countedPoints++
}
else -> userLocations.locationsByType.values.firstOrNull()?.forEach {
dist += it.distanceFromPrev
countedPoints++
}
}
return dist.toFloat()
return Pair(dist.toFloat(), countedPoints)
}
override fun getItemCount() = items.size

View file

@ -20,12 +20,10 @@ import android.widget.Toast
import net.osmand.PlatformUtil
import net.osmand.aidl.gpx.AGpxBitmap
import net.osmand.telegram.R
import net.osmand.telegram.helpers.LocationMessages
import net.osmand.telegram.helpers.OsmandAidlHelper
import net.osmand.telegram.helpers.TelegramUiHelper
import net.osmand.telegram.utils.AndroidUtils
import net.osmand.telegram.utils.GPXUtilities
import net.osmand.telegram.utils.OsmandFormatter
import net.osmand.telegram.utils.OsmandLocationUtils
import net.osmand.telegram.utils.*
import net.osmand.util.Algorithms
import java.io.File
import java.text.SimpleDateFormat
@ -52,6 +50,8 @@ class UserGpxInfoFragment : BaseDialogFragment() {
private var startCalendar = Calendar.getInstance()
private var endCalendar = Calendar.getInstance()
private var locationMessages = emptyList<LocationMessages.LocationMessage>()
private var userId = -1
private var chatId = -1L
@ -115,10 +115,10 @@ class UserGpxInfoFragment : BaseDialogFragment() {
setImageDrawable(uiUtils.getThemedIcon(R.drawable.ic_action_speed_average))
}
mainView.findViewById<ImageView>(R.id.distance_icon).apply {
setImageDrawable(uiUtils.getThemedIcon(R.drawable.ic_action_altitude_range))
setImageDrawable(uiUtils.getThemedIcon(R.drawable.ic_action_sort_by_distance))
}
mainView.findViewById<ImageView>(R.id.duration_icon).apply {
setImageDrawable(uiUtils.getThemedIcon(R.drawable.ic_action_altitude_range))
setImageDrawable(uiUtils.getThemedIcon(R.drawable.ic_action_time_span))
}
updateGPXStatisticRow()
@ -192,7 +192,8 @@ class UserGpxInfoFragment : BaseDialogFragment() {
private fun saveCurrentGpxToFile(listener: OsmandLocationUtils.SaveGpxListener) {
if (!gpxFile.isEmpty) {
OsmandLocationUtils.saveGpx(app, listener, app.getExternalFilesDir(null)!!, gpxFile)
val file = File(app.getExternalFilesDir(null), TRACKS_DIR)
OsmandLocationUtils.saveGpx(app, listener, file, gpxFile)
}
}
@ -210,10 +211,9 @@ class UserGpxInfoFragment : BaseDialogFragment() {
}
private fun updateGpxInfo() {
val emm = app.locationMessages.getMessagesForUserInChat(
userId, chatId, startCalendar.timeInMillis, endCalendar.timeInMillis)
locationMessages = app.locationMessages.getMessagesForUserInChat(userId, chatId, startCalendar.timeInMillis, endCalendar.timeInMillis)
gpxFile = OsmandLocationUtils.convertLocationMessagesToGpxFiles(emm).firstOrNull()?:GPXUtilities.GPXFile()
gpxFile = OsmandLocationUtils.convertLocationMessagesToGpxFiles(locationMessages).firstOrNull()?:GPXUtilities.GPXFile()
updateGPXStatisticRow()
updateDateAndTimeButtons()
updateGPXMap()
@ -246,7 +246,9 @@ class UserGpxInfoFragment : BaseDialogFragment() {
val widthPixels = dm.widthPixels - (2 * app.resources.getDimensionPixelSize(R.dimen.content_padding_standard))
val heightPixels = AndroidUtils.dpToPx(app, 152f)
val gpxUri = AndroidUtils.getUriForFile(app, File(path))
app.osmandAidlHelper.getBitmapForGpx(gpxUri, dm.density , widthPixels, heightPixels, GPX_TRACK_COLOR)
app.osmandAidlHelper.execOsmandApi {
app.osmandAidlHelper.getBitmapForGpx(gpxUri, dm.density , widthPixels, heightPixels, GPX_TRACK_COLOR)
}
}
}

View file

@ -2,6 +2,7 @@ package net.osmand.telegram.utils
import android.os.AsyncTask
import net.osmand.Location
import net.osmand.data.LatLon
import net.osmand.telegram.TelegramApplication
import net.osmand.telegram.helpers.LocationMessages
import net.osmand.telegram.helpers.LocationMessages.BufferMessage
@ -15,6 +16,7 @@ import java.io.File
import java.text.SimpleDateFormat
import java.util.*
const val TRACKS_DIR = "tracker/"
object OsmandLocationUtils {
@ -83,10 +85,11 @@ object OsmandLocationUtils {
lat = messageLocation.location.latitude
lon = messageLocation.location.longitude
lastUpdated = getLastUpdatedTime(message)
type = LocationMessages.TYPE_USER_MAP
}
}
fun parseMessage(message: TdApi.Message, helper: TelegramHelper, previousMessage: LocationMessage?): LocationMessage? {
fun parseMessage(message: TdApi.Message, helper: TelegramHelper, previousMessageLatLon: LatLon?): LocationMessage? {
var locationMessage: LocationMessage? = null
val oldContent = message.content
val messageType = getMessageType(message,helper)
@ -114,10 +117,8 @@ object OsmandLocationUtils {
}
if (parsedMessageContent != null) {
val distanceFromPrev = if (previousMessage != null) {
MapUtils.getDistance(previousMessage.lat, previousMessage.lon,
parsedMessageContent.lat, parsedMessageContent.lon)
} else 0.0
val distanceFromPrev = if (previousMessageLatLon != null) {
MapUtils.getDistance(previousMessageLatLon, parsedMessageContent.lat, parsedMessageContent.lon) } else 0.0
locationMessage = LocationMessage(helper.getSenderMessageId(message), message.chatId, parsedMessageContent.lat,
parsedMessageContent.lon, parsedMessageContent.altitude, parsedMessageContent.speed, parsedMessageContent.hdop,
@ -403,11 +404,16 @@ object OsmandLocationUtils {
var segment: GPXUtilities.TrkSegment? = null
var track: GPXUtilities.Track? = null
var gpx: GPXUtilities.GPXFile? = null
var countedLocations = 0
items.forEach {
val userId = it.userId
val chatId = it.chatId
val time = it.time
if (previousTime >= time) {
return@forEach
}
countedLocations++
if (previousUserId != userId || (newGpxPerChat && previousChatId != chatId)) {
gpx = GPXUtilities.GPXFile()
gpx!!.chatId = chatId
@ -521,10 +527,6 @@ object OsmandLocationUtils {
userId.toString() + "_" + SimpleDateFormat("yyyy-MM-dd_HH-mm_EEE", Locale.US).format(Date(pt.time))
}
fout = File(dir, "$fileName.gpx")
var ind = 1
while (fout.exists()) {
fout = File(dir, "${fileName}_${++ind}.gpx")
}
}
val warn = GPXUtilities.writeGpxFile(fout, gpxFile, app)
if (warn != null) {