diff --git a/OsmAnd-telegram/res/layout/my_location_sharing_chat.xml b/OsmAnd-telegram/res/layout/my_location_sharing_chat.xml
index 08d8a25c1d..0f70f54286 100644
--- a/OsmAnd-telegram/res/layout/my_location_sharing_chat.xml
+++ b/OsmAnd-telegram/res/layout/my_location_sharing_chat.xml
@@ -171,6 +171,63 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Collected
+ Gps points
+ Sent
Monitoring is enabled
Monitoring is disabled
time on the move
diff --git a/OsmAnd-telegram/src/net/osmand/telegram/TelegramApplication.kt b/OsmAnd-telegram/src/net/osmand/telegram/TelegramApplication.kt
index 2addc53573..33758e4ad3 100644
--- a/OsmAnd-telegram/src/net/osmand/telegram/TelegramApplication.kt
+++ b/OsmAnd-telegram/src/net/osmand/telegram/TelegramApplication.kt
@@ -24,8 +24,7 @@ class TelegramApplication : Application(), OsmandHelperListener {
lateinit var notificationHelper: NotificationHelper private set
lateinit var osmandAidlHelper: OsmandAidlHelper private set
lateinit var locationProvider: TelegramLocationProvider private set
- lateinit var messagesDbHelper: MessagesDbHelper private set
- lateinit var savingTracksDbHelper: SavingTracksDbHelper private set
+ lateinit var locationMessages: LocationMessages private set
var telegramService: TelegramService? = null
@@ -68,8 +67,7 @@ class TelegramApplication : Application(), OsmandHelperListener {
showLocationHelper = ShowLocationHelper(this)
notificationHelper = NotificationHelper(this)
locationProvider = TelegramLocationProvider(this)
- messagesDbHelper = MessagesDbHelper(this)
- savingTracksDbHelper = SavingTracksDbHelper(this)
+ locationMessages = LocationMessages(this)
if (settings.hasAnyChatToShareLocation() && AndroidUtils.isLocationPermissionAvailable(this)) {
shareLocationHelper.startSharingLocation()
@@ -96,6 +94,13 @@ class TelegramApplication : Application(), OsmandHelperListener {
return ni != null && ni.type == ConnectivityManager.TYPE_WIFI
}
+ val isMobileConnected: Boolean
+ get() {
+ val mgr = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
+ val ni = mgr.activeNetworkInfo
+ return ni != null && ni.type == ConnectivityManager.TYPE_MOBILE
+ }
+
private val isInternetConnected: Boolean
get() {
val mgr = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
diff --git a/OsmAnd-telegram/src/net/osmand/telegram/TelegramService.kt b/OsmAnd-telegram/src/net/osmand/telegram/TelegramService.kt
index 4b90dd5a93..e6c2ebc7e4 100644
--- a/OsmAnd-telegram/src/net/osmand/telegram/TelegramService.kt
+++ b/OsmAnd-telegram/src/net/osmand/telegram/TelegramService.kt
@@ -13,10 +13,12 @@ import android.os.*
import android.util.Log
import android.widget.Toast
import net.osmand.PlatformUtil
-import net.osmand.telegram.helpers.TelegramHelper.TelegramOutgoingMessagesListener
+import net.osmand.telegram.helpers.LocationMessages
import net.osmand.telegram.helpers.TelegramHelper.TelegramIncomingMessagesListener
+import net.osmand.telegram.helpers.TelegramHelper.TelegramOutgoingMessagesListener
import net.osmand.telegram.notifications.TelegramNotification.NotificationType
import net.osmand.telegram.utils.AndroidUtils
+import net.osmand.telegram.utils.OsmandLocationUtils
import org.drinkless.td.libcore.telegram.TdApi
import java.util.*
@@ -120,6 +122,7 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
override fun onDestroy() {
super.onDestroy()
val app = app()
+ app.locationMessages.saveMessages()
app.telegramHelper.stopLiveMessagesUpdates()
app.telegramHelper.removeIncomingMessagesListener(this)
app.telegramHelper.removeOutgoingMessagesListener(this)
@@ -274,6 +277,12 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
override fun onReceiveChatLocationMessages(chatId: Long, vararg messages: TdApi.Message) {
app().showLocationHelper.startShowMessagesTask(chatId, *messages)
+ messages.forEach {
+ val locationMessage = OsmandLocationUtils.parseMessage(it, app().telegramHelper, LocationMessages.LocationMessage.STATUS_SENT)
+ if (locationMessage != null) {
+ app().locationMessages.addLocationMessage(locationMessage)
+ }
+ }
}
override fun onDeleteChatLocationMessages(chatId: Long, messages: List) {
diff --git a/OsmAnd-telegram/src/net/osmand/telegram/TelegramSettings.kt b/OsmAnd-telegram/src/net/osmand/telegram/TelegramSettings.kt
index 8b9cb02a60..f25f7c93d5 100644
--- a/OsmAnd-telegram/src/net/osmand/telegram/TelegramSettings.kt
+++ b/OsmAnd-telegram/src/net/osmand/telegram/TelegramSettings.kt
@@ -851,6 +851,7 @@ class TelegramSettings(private val app: TelegramApplication) {
var lastSuccessfulSendTimeMs = -1L
var lastSendTextMessageTime = -1
var lastSendMapMessageTime = -1
+ var bufferedMessages = 0
var pendingTextMessage = false
var pendingMapMessage = false
var shouldSendViaBotMessage = false
diff --git a/OsmAnd-telegram/src/net/osmand/telegram/helpers/LocationMessages.kt b/OsmAnd-telegram/src/net/osmand/telegram/helpers/LocationMessages.kt
new file mode 100644
index 0000000000..bf49ff9725
--- /dev/null
+++ b/OsmAnd-telegram/src/net/osmand/telegram/helpers/LocationMessages.kt
@@ -0,0 +1,220 @@
+package net.osmand.telegram.helpers
+
+import android.content.Context
+import android.database.Cursor
+import android.database.sqlite.SQLiteDatabase
+import android.database.sqlite.SQLiteOpenHelper
+import net.osmand.PlatformUtil
+import net.osmand.telegram.TelegramApplication
+import org.apache.commons.logging.Log
+import java.util.*
+
+class LocationMessages(val app: TelegramApplication) {
+
+ private val log: Log = PlatformUtil.getLog(LocationMessages::class.java)
+
+ private val locationMessages = ArrayList()
+
+ private val sqliteHelper: SQLiteHelper
+
+ init {
+ sqliteHelper = SQLiteHelper(app)
+ readMessages()
+ }
+
+ fun getLocationMessages(): List {
+ return this.locationMessages
+ }
+
+ fun getPreparedToShareMessages(): List {
+ val currentUserId = app.telegramHelper.getCurrentUserId()
+ return locationMessages.filter { it.userId == currentUserId && it.status == LocationMessage.STATUS_PREPARING }.sortedBy { it.date }
+ }
+
+ fun getOutgoingMessagesToChat(chatId: Long): List {
+ val currentUserId = app.telegramHelper.getCurrentUserId()
+ return locationMessages.filter { it.userId == currentUserId && it.chatId == chatId }.sortedBy { it.date }
+ }
+
+ fun getOutgoingMessagesToChatFromDate(chatId: Long, date:Long): List {
+ val currentUserId = app.telegramHelper.getCurrentUserId()
+ return locationMessages.filter { it.userId == currentUserId && it.chatId == chatId && it.date > date }.sortedBy { it.date }
+ }
+
+ fun getSentOutgoingMessagesToChat(chatId: Long): List {
+ val currentUserId = app.telegramHelper.getCurrentUserId()
+ return locationMessages.filter { it.userId == currentUserId && it.chatId == chatId && it.status == LocationMessages.LocationMessage.STATUS_SENT }.sortedBy { it.date }
+ }
+
+ fun getIncomingMessages(): List {
+ val currentUserId = app.telegramHelper.getCurrentUserId()
+ return locationMessages.filter { it.userId != currentUserId }.sortedBy { it.date }
+ }
+
+ fun addLocationMessage(locationMessage: LocationMessage) {
+ log.debug("addLocationMessage $locationMessage")
+ synchronized(locationMessages) {
+ locationMessages.add(locationMessage)
+ }
+ }
+
+ fun removeMessage(locationMessage: LocationMessage) {
+ synchronized(locationMessages) {
+ locationMessages.remove(locationMessage)
+ }
+ }
+
+ fun saveMessages() {
+ clearMessages()
+ synchronized(locationMessages) {
+ sqliteHelper.addLocationMessages(locationMessages)
+ }
+ }
+
+ fun clearMessages() {
+ sqliteHelper.clearLocationMessages()
+ }
+
+ fun collectRecordedDataForUser(userId: Int, chatId: Long, start: Long, end: Long): List {
+ return if (chatId == 0L) {
+ locationMessages.sortedWith(compareBy({ it.userId }, { it.chatId })).filter { it.userId == userId&&it.date in (start + 1)..(end - 1) }
+ } else {
+ locationMessages.sortedWith(compareBy({ it.userId }, { it.chatId })).filter {
+ it.chatId == chatId && it.userId == userId && it.status == LocationMessage.STATUS_SENT && it.date in (start + 1)..(end - 1) }
+ }
+ }
+
+ fun collectRecordedDataForUsers(start: Long, end: Long, ignoredUsersIds: ArrayList): List {
+ return locationMessages.sortedWith(compareBy({ it.userId }, { it.chatId })).filter {
+ it.date in (start + 1)..(end - 1) && !ignoredUsersIds.contains(it.userId)
+ }
+ }
+
+ private fun readMessages() {
+ val messages = sqliteHelper.getLocationMessages()
+ synchronized(locationMessages) {
+ locationMessages.addAll(messages)
+ }
+ }
+
+ private class SQLiteHelper(context: Context) :
+ SQLiteOpenHelper(context, DATABASE_NAME, null, DATABASE_VERSION) {
+
+ override fun onCreate(db: SQLiteDatabase) {
+ db.execSQL(TRACKS_TABLE_CREATE)
+ db.execSQL("CREATE INDEX $TRACK_DATE_INDEX ON $TRACK_TABLE_NAME (\"$TRACK_COL_DATE\" DESC);")
+ }
+
+ override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
+ db.execSQL(TRACKS_TABLE_DELETE)
+ onCreate(db)
+ }
+
+ internal fun addLocationMessages(locationMessages: List) {
+ locationMessages.forEach {
+ writableDatabase?.execSQL(TRACKS_TABLE_INSERT,
+ arrayOf(it.userId, it.chatId, it.lat, it.lon, it.altitude, it.speed, it.hdop, it.bearing, it.date, it.type, it.status, it.messageId))
+ }
+ }
+
+ internal fun getLocationMessages(): Set {
+ val res = HashSet()
+ readableDatabase?.rawQuery(TRACKS_TABLE_SELECT, null)?.apply {
+ if (moveToFirst()) {
+ do {
+ res.add(readLocationMessage(this@apply))
+ } while (moveToNext())
+ }
+ close()
+ }
+ return res
+ }
+
+ internal fun readLocationMessage(cursor: Cursor): LocationMessage {
+ val userId = cursor.getInt(0)
+ val chatId = cursor.getLong(1)
+ val lat = cursor.getDouble(2)
+ val lon = cursor.getDouble(3)
+ val altitude = cursor.getDouble(4)
+ val speed = cursor.getDouble(5)
+ val hdop = cursor.getDouble(6)
+ val date = cursor.getLong(7)
+ val bearing = cursor.getDouble(8)
+ val textInfo = cursor.getInt(9)
+ val status = cursor.getInt(10)
+ val messageId = cursor.getLong(11)
+
+ return LocationMessage(userId, chatId, lat, lon, altitude, speed, hdop, bearing, date, textInfo, status, messageId)
+ }
+
+ internal fun clearLocationMessages() {
+ writableDatabase?.execSQL(TRACKS_TABLE_CLEAR)
+ }
+
+ companion object {
+
+ private const val DATABASE_NAME = "location_messages"
+ private const val DATABASE_VERSION = 2
+
+ private const val TRACK_TABLE_NAME = "track"
+ private const val TRACK_COL_USER_ID = "user_id"
+ private const val TRACK_COL_CHAT_ID = "chat_id"
+ private const val TRACK_COL_DATE = "date"
+ private const val TRACK_COL_LAT = "lat"
+ private const val TRACK_COL_LON = "lon"
+ private const val TRACK_COL_ALTITUDE = "altitude"
+ private const val TRACK_COL_SPEED = "speed"
+ private const val TRACK_COL_HDOP = "hdop"
+ private const val TRACK_COL_BEARING = "bearing"
+ private const val TRACK_COL_TYPE =
+ "type" // 0 = user map message, 1 = user text message, 2 = bot map message, 3 = bot text message
+ private const val TRACK_COL_MESSAGE_STATUS =
+ "status" // 0 = preparing , 1 = pending, 2 = sent, 3 = error
+ private const val TRACK_COL_MESSAGE_ID = "message_id"
+
+ private const val TRACK_DATE_INDEX = "date_index"
+
+ private const val TRACKS_TABLE_INSERT =
+ ("INSERT INTO $TRACK_TABLE_NAME ($TRACK_COL_USER_ID, $TRACK_COL_CHAT_ID, $TRACK_COL_LAT, $TRACK_COL_LON, $TRACK_COL_ALTITUDE, $TRACK_COL_SPEED, $TRACK_COL_HDOP, $TRACK_COL_BEARING, $TRACK_COL_DATE, $TRACK_COL_TYPE, $TRACK_COL_MESSAGE_STATUS, $TRACK_COL_MESSAGE_ID) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
+
+ private const val TRACKS_TABLE_CREATE =
+ ("CREATE TABLE IF NOT EXISTS $TRACK_TABLE_NAME ($TRACK_COL_USER_ID long, $TRACK_COL_CHAT_ID long,$TRACK_COL_LAT double, $TRACK_COL_LON double, $TRACK_COL_ALTITUDE double, $TRACK_COL_SPEED float, $TRACK_COL_HDOP double, $TRACK_COL_BEARING double, $TRACK_COL_DATE long, $TRACK_COL_TYPE int, $TRACK_COL_MESSAGE_STATUS int, $TRACK_COL_MESSAGE_ID long )")
+
+ private const val TRACKS_TABLE_SELECT =
+ "SELECT $TRACK_COL_USER_ID, $TRACK_COL_CHAT_ID, $TRACK_COL_LAT, $TRACK_COL_LON, $TRACK_COL_ALTITUDE, $TRACK_COL_SPEED, $TRACK_COL_HDOP, $TRACK_COL_BEARING, $TRACK_COL_DATE, $TRACK_COL_TYPE, $TRACK_COL_MESSAGE_STATUS, $TRACK_COL_MESSAGE_ID FROM $TRACK_TABLE_NAME"
+
+ private const val TRACKS_TABLE_CLEAR = "DELETE FROM $TRACK_TABLE_NAME"
+
+ private const val TRACKS_TABLE_DELETE = "DROP TABLE IF EXISTS $TRACK_TABLE_NAME"
+ }
+ }
+
+ data class LocationMessage(
+ val userId: Int,
+ val chatId: Long,
+ val lat: Double,
+ val lon: Double,
+ val altitude: Double,
+ val speed: Double,
+ val hdop: Double,
+ val bearing: Double,
+ val date: Long,
+ val type: Int,
+ var status: Int,
+ var messageId: Long
+ ) {
+
+ companion object {
+
+ const val STATUS_PREPARING = 0
+ const val STATUS_PENDING = 1
+ const val STATUS_SENT = 2
+ const val STATUS_ERROR = 3
+
+ const val TYPE_USER_MAP = 0
+ const val TYPE_USER_TEXT = 1
+ const val TYPE_BOT_MAP = 2
+ const val TYPE_BOT_TEXT = 3
+ }
+ }
+}
\ No newline at end of file
diff --git a/OsmAnd-telegram/src/net/osmand/telegram/helpers/MessagesDbHelper.kt b/OsmAnd-telegram/src/net/osmand/telegram/helpers/MessagesDbHelper.kt
deleted file mode 100644
index dcd4d67c46..0000000000
--- a/OsmAnd-telegram/src/net/osmand/telegram/helpers/MessagesDbHelper.kt
+++ /dev/null
@@ -1,122 +0,0 @@
-package net.osmand.telegram.helpers
-
-import android.content.Context
-import android.database.sqlite.SQLiteDatabase
-import android.database.sqlite.SQLiteOpenHelper
-import net.osmand.telegram.TelegramApplication
-import org.drinkless.td.libcore.telegram.TdApi
-
-class MessagesDbHelper(val app: TelegramApplication) {
-
- private val messages = HashSet()
-
- private val sqliteHelper: SQLiteHelper
-
- init {
- sqliteHelper = SQLiteHelper(app)
- sqliteHelper.getMessages().forEach {
- app.telegramHelper.loadMessage(it.chatId, it.messageId)
- }
- app.telegramHelper.addIncomingMessagesListener(object :
- TelegramHelper.TelegramIncomingMessagesListener {
-
- override fun onReceiveChatLocationMessages(
- chatId: Long, vararg messages: TdApi.Message
- ) {
- messages.forEach { addMessage(chatId, it.id) }
- }
-
- override fun onDeleteChatLocationMessages(chatId: Long, messages: List) {
- messages.forEach { removeMessage(chatId, it.id) }
- }
-
- override fun updateLocationMessages() {}
- })
- }
-
- fun saveMessages() {
- clearMessages()
- synchronized(messages) {
- sqliteHelper.addMessages(messages)
- }
- }
-
- fun clearMessages() {
- sqliteHelper.clearMessages()
- }
-
- private fun addMessage(chatId: Long, messageId: Long) {
- synchronized(messages) {
- messages.add(Message(chatId, messageId))
- }
- }
-
- private fun removeMessage(chatId: Long, messageId: Long) {
- synchronized(messages) {
- messages.remove(Message(chatId, messageId))
- }
- }
-
- private class SQLiteHelper(context: Context) :
- SQLiteOpenHelper(context, DB_NAME, null, DB_VERSION) {
-
- override fun onCreate(db: SQLiteDatabase) {
- db.execSQL(MESSAGES_TABLE_CREATE)
- }
-
- override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
- db.execSQL(MESSAGES_TABLE_DELETE)
- onCreate(db)
- }
-
- internal fun addMessages(messages: Set) {
- messages.forEach {
- writableDatabase?.execSQL(MESSAGES_TABLE_INSERT, arrayOf(it.chatId, it.messageId))
- }
- }
-
- internal fun getMessages(): Set {
- val res = HashSet()
- readableDatabase?.rawQuery(MESSAGES_TABLE_SELECT, null)?.apply {
- if (moveToFirst()) {
- do {
- res.add(Message(getLong(0), getLong(1)))
- } while (moveToNext())
- }
- close()
- }
- return res
- }
-
- internal fun clearMessages() {
- writableDatabase?.execSQL(MESSAGES_TABLE_CLEAR)
- }
-
- companion object {
-
- private const val DB_NAME = "messages.db"
- private const val DB_VERSION = 1
-
- private const val MESSAGES_TABLE_NAME = "messages"
- private const val MESSAGES_COL_CHAT_ID = "chat_id"
- private const val MESSAGES_COL_MESSAGE_ID = "message_id"
-
- private const val MESSAGES_TABLE_CREATE =
- "CREATE TABLE IF NOT EXISTS $MESSAGES_TABLE_NAME (" +
- "$MESSAGES_COL_CHAT_ID LONG, " +
- "$MESSAGES_COL_MESSAGE_ID LONG)"
-
- private const val MESSAGES_TABLE_DELETE = "DROP TABLE IF EXISTS $MESSAGES_TABLE_NAME"
-
- private const val MESSAGES_TABLE_SELECT =
- "SELECT $MESSAGES_COL_CHAT_ID, $MESSAGES_COL_MESSAGE_ID FROM $MESSAGES_TABLE_NAME"
-
- private const val MESSAGES_TABLE_CLEAR = "DELETE FROM $MESSAGES_TABLE_NAME"
-
- private const val MESSAGES_TABLE_INSERT = "INSERT INTO $MESSAGES_TABLE_NAME (" +
- "$MESSAGES_COL_CHAT_ID, $MESSAGES_COL_MESSAGE_ID) VALUES (?, ?)"
- }
- }
-
- private data class Message(val chatId: Long, val messageId: Long)
-}
diff --git a/OsmAnd-telegram/src/net/osmand/telegram/helpers/SavingTracksDbHelper.java b/OsmAnd-telegram/src/net/osmand/telegram/helpers/SavingTracksDbHelper.java
deleted file mode 100644
index feac28fe39..0000000000
--- a/OsmAnd-telegram/src/net/osmand/telegram/helpers/SavingTracksDbHelper.java
+++ /dev/null
@@ -1,476 +0,0 @@
-package net.osmand.telegram.helpers;
-
-import android.database.Cursor;
-import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteOpenHelper;
-import android.os.AsyncTask;
-
-import net.osmand.PlatformUtil;
-import net.osmand.telegram.TelegramApplication;
-import net.osmand.telegram.utils.GPXUtilities;
-import net.osmand.telegram.utils.GPXUtilities.GPXFile;
-import net.osmand.telegram.utils.GPXUtilities.Track;
-import net.osmand.telegram.utils.GPXUtilities.TrkSegment;
-import net.osmand.telegram.utils.GPXUtilities.WptPt;
-
-import org.apache.commons.logging.Log;
-import org.drinkless.td.libcore.telegram.TdApi;
-import org.jetbrains.annotations.NotNull;
-
-import java.io.File;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-import java.util.Locale;
-
-public class SavingTracksDbHelper extends SQLiteOpenHelper {
-
- private final static String DATABASE_NAME = "tracks";
- private final static int DATABASE_VERSION = 3;
-
- private final static String TRACK_NAME = "track"; //$NON-NLS-1$
- private final static String TRACK_COL_USER_ID = "user_id"; //$NON-NLS-1$
- private final static String TRACK_COL_CHAT_ID = "chat_id"; //$NON-NLS-1$
- private final static String TRACK_COL_DATE = "date"; //$NON-NLS-1$
- private final static String TRACK_COL_LAT = "lat"; //$NON-NLS-1$
- private final static String TRACK_COL_LON = "lon"; //$NON-NLS-1$
- private final static String TRACK_COL_ALTITUDE = "altitude"; //$NON-NLS-1$
- private final static String TRACK_COL_SPEED = "speed"; //$NON-NLS-1$
- private final static String TRACK_COL_HDOP = "hdop"; //$NON-NLS-1$
- private final static String TRACK_COL_TEXT_INFO = "text_info"; // 1 = true, 0 = false //$NON-NLS-1$
-
- private final static String INSERT_SCRIPT = "INSERT INTO " + TRACK_NAME + " (" + TRACK_COL_USER_ID + ", " + TRACK_COL_CHAT_ID + ", " + TRACK_COL_LAT + ", " + TRACK_COL_LON + ", "
- + TRACK_COL_ALTITUDE + ", " + TRACK_COL_SPEED + ", " + TRACK_COL_HDOP + ", " + TRACK_COL_DATE + ", " + TRACK_COL_TEXT_INFO + ")"
- + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
-
- private final static String CREATE_SCRIPT = "CREATE TABLE " + TRACK_NAME + " (" + TRACK_COL_USER_ID + " long," + TRACK_COL_CHAT_ID + " long," + TRACK_COL_LAT + " double, " + TRACK_COL_LON + " double, " //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$//$NON-NLS-5$
- + TRACK_COL_ALTITUDE + " double, " + TRACK_COL_SPEED + " double, " //$NON-NLS-1$ //$NON-NLS-2$
- + TRACK_COL_HDOP + " double, " + TRACK_COL_DATE + " long, " + TRACK_COL_TEXT_INFO + " int )";
-
- private final static Log log = PlatformUtil.getLog(SavingTracksDbHelper.class);
-
- private final TelegramApplication app;
-
- public SavingTracksDbHelper(TelegramApplication app) {
- super(app, DATABASE_NAME, null, DATABASE_VERSION);
- this.app = app;
-
- app.getTelegramHelper().addIncomingMessagesListener(new TelegramHelper.TelegramIncomingMessagesListener() {
-
- @Override
- public void onReceiveChatLocationMessages(long chatId, @NotNull TdApi.Message... messages) {
- for (TdApi.Message message : messages) {
- updateLocationMessage(message);
- }
- }
-
- @Override
- public void onDeleteChatLocationMessages(long chatId, @NotNull List extends TdApi.Message> messages) {
-
- }
-
- @Override
- public void updateLocationMessages() {
-
- }
- });
- app.getTelegramHelper().addOutgoingMessagesListener(new TelegramHelper.TelegramOutgoingMessagesListener() {
-
- @Override
- public void onUpdateMessages(@NotNull List extends TdApi.Message> messages) {
- for (TdApi.Message message : messages) {
- updateLocationMessage(message);
- }
- }
-
- @Override
- public void onDeleteMessages(long chatId, @NotNull List messages) {
-
- }
-
- @Override
- public void onSendLiveLocationError(int code, @NotNull String message) {
-
- }
- });
- }
-
- @Override
- public void onCreate(SQLiteDatabase db) {
- db.execSQL(CREATE_SCRIPT);
- }
-
- @Override
- public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- if (oldVersion < 3) {
- db.execSQL("ALTER TABLE " + TRACK_NAME + " ADD " + TRACK_COL_TEXT_INFO + " int");
- }
- }
-
- public void saveUserDataToGpx(SaveGpxListener listener, File dir, int userId, long chatId, long start, long end) {
- GPXFile gpxFile = collectRecordedDataForUserAndChat(userId, chatId, start, end);
- if (gpxFile != null && !gpxFile.isEmpty()) {
- SaveGPXTrackToFileTask task = new SaveGPXTrackToFileTask(app, listener, gpxFile, dir, userId);
- task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- }
- }
-
- public void saveGpx(SaveGpxListener listener, File dir, GPXFile gpxFile) {
- if (gpxFile != null && !gpxFile.isEmpty()) {
- SaveGPXTrackToFileTask task = new SaveGPXTrackToFileTask(app, listener, gpxFile, dir, 0);
- task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- }
- }
-
- private void updateLocationMessage(TdApi.Message message) {
- log.debug(message);
- TdApi.MessageContent content = message.content;
- int senderId = app.getTelegramHelper().getSenderMessageId(message);
- if (content instanceof TdApi.MessageLocation) {
- long lastTextMessageUpdate = getLastTextTrackPointTimeForUser(message.senderUserId);
- long currentTime = System.currentTimeMillis();
- if (lastTextMessageUpdate == 0 || currentTime - lastTextMessageUpdate < 10 * 1000) {
- log.debug("Add map message " + message.senderUserId);
- TdApi.MessageLocation messageLocation = (TdApi.MessageLocation) content;
- insertData(senderId, message.chatId, messageLocation.location.latitude,
- messageLocation.location.longitude, 0.0, 0.0, 0.0,
- Math.max(message.date, message.editDate), 0);
- } else {
- log.debug("Skip map message");
- }
- } else if (content instanceof TelegramHelper.MessageLocation) {
- log.debug("Add text message " + message.senderUserId);
- TelegramHelper.MessageLocation messageLocation = (TelegramHelper.MessageLocation) content;
- insertData(senderId, message.chatId, messageLocation.getLat(), messageLocation.getLon(),
- messageLocation.getAltitude(), messageLocation.getSpeed(), messageLocation.getHdop(),
- messageLocation.getLastUpdated() * 1000L, 1);
- }
- }
-
- private void insertData(int userId, long chatId, double lat, double lon, double alt, double speed, double hdop, long time, int textMessage) {
- execWithClose(INSERT_SCRIPT, new Object[]{userId, chatId, lat, lon, alt, speed, hdop, time, textMessage});
- }
-
- private synchronized void execWithClose(String script, Object[] objects) {
- SQLiteDatabase db = getWritableDatabase();
- try {
- if (db != null) {
- db.execSQL(script, objects);
- }
- } catch (RuntimeException e) {
- log.error(e.getMessage(), e);
- } finally {
- if (db != null) {
- db.close();
- }
- }
- }
-
- private long getLastTextTrackPointTimeForUser(int userId) {
- long res = 0;
- try {
- SQLiteDatabase db = getWritableDatabase();
- if (db != null) {
- try {
- Cursor query = db.rawQuery("SELECT " + TRACK_COL_DATE + " FROM " + TRACK_NAME + " WHERE " + TRACK_COL_USER_ID + " = ? AND "
- + TRACK_COL_TEXT_INFO + " = ?" + " ORDER BY " + TRACK_COL_DATE + " ASC ", new String[]{String.valueOf(userId), String.valueOf(1)});
- if (query.moveToFirst()) {
- res = query.getLong(0);
- }
- query.close();
- } finally {
- db.close();
- }
- }
- } catch (RuntimeException e) {
- }
- return res;
- }
-
- public GPXFile collectRecordedDataForUserAndChat(int userId, long chatId, long start, long end) {
- GPXFile gpxFile = null;
- SQLiteDatabase db = getReadableDatabase();
- if (db != null && db.isOpen()) {
- try {
- gpxFile = collectDBTracksForUser(db, userId, chatId, start, end);
- } finally {
- db.close();
- }
- }
- return gpxFile;
- }
-
- public GPXFile collectRecordedDataForUser(int userId, long chatId, long start, long end) {
- GPXFile gpxFile = null;
- SQLiteDatabase db = getReadableDatabase();
- if (db != null && db.isOpen()) {
- try {
- if (chatId == 0) {
- gpxFile = collectDBTracksForUser(db, userId, start, end);
- } else {
- gpxFile = collectDBTracksForUser(db, userId, chatId, start, end);
- }
- } finally {
- db.close();
- }
- }
- return gpxFile;
- }
-
- public ArrayList collectRecordedDataForUsers(long start, long end, ArrayList ignoredUsersIds) {
- ArrayList data = new ArrayList<>();
- SQLiteDatabase db = getReadableDatabase();
- if (db != null && db.isOpen()) {
- try {
- collectDBTracksForUsers(db, data, start, end, ignoredUsersIds);
- } finally {
- db.close();
- }
- }
- return data;
- }
-
- private GPXFile collectDBTracksForUser(SQLiteDatabase db, int userId, long chatId, long start, long end) {
- Cursor query = db.rawQuery("SELECT " + TRACK_COL_USER_ID + "," + TRACK_COL_CHAT_ID + ","
- + TRACK_COL_LAT + "," + TRACK_COL_LON + "," + TRACK_COL_ALTITUDE + "," + TRACK_COL_SPEED + ","
- + TRACK_COL_HDOP + "," + TRACK_COL_DATE + " FROM " + TRACK_NAME + " WHERE " + TRACK_COL_USER_ID + " = ?"
- + " AND " + TRACK_COL_CHAT_ID + " = ?" + " AND " + TRACK_COL_DATE + " BETWEEN " + start + " AND " + end
- + " ORDER BY " + TRACK_COL_DATE + " ASC ", new String[]{String.valueOf(userId), String.valueOf(chatId)});
-
- GPXFile gpxFile = null;
- long previousTime = 0;
- TrkSegment segment = null;
- Track track = null;
- if (query.moveToFirst()) {
- gpxFile = new GPXFile();
- gpxFile.chatId = chatId;
- gpxFile.userId = userId;
- do {
- long time = query.getLong(7);
- WptPt pt = new WptPt();
- pt.userId = query.getInt(0);
- pt.chatId = query.getLong(1);
- pt.lat = query.getDouble(2);
- pt.lon = query.getDouble(3);
- pt.ele = query.getDouble(4);
- pt.speed = query.getDouble(5);
- pt.hdop = query.getDouble(6);
- pt.time = time;
- long currentInterval = Math.abs(time - previousTime);
-
- if (track != null) {
- if (currentInterval < 30 * 60 * 1000) {
- // 30 minute - same segment
- segment.points.add(pt);
- } else {
- segment = new TrkSegment();
- segment.points.add(pt);
- track.segments.add(segment);
- }
- } else {
- track = new Track();
- segment = new TrkSegment();
- track.segments.add(segment);
- segment.points.add(pt);
-
- gpxFile.tracks.add(track);
- }
- previousTime = time;
- } while (query.moveToNext());
- }
- query.close();
- return gpxFile;
- }
-
- private GPXFile collectDBTracksForUser(SQLiteDatabase db, int userId, long start, long end) {
- Cursor query = db.rawQuery("SELECT " + TRACK_COL_USER_ID + "," + TRACK_COL_CHAT_ID + ","
- + TRACK_COL_LAT + "," + TRACK_COL_LON + "," + TRACK_COL_ALTITUDE + "," + TRACK_COL_SPEED + ","
- + TRACK_COL_HDOP + "," + TRACK_COL_DATE + " FROM " + TRACK_NAME + " WHERE " + TRACK_COL_USER_ID + " = ?"
- + " AND " + TRACK_COL_DATE + " BETWEEN " + start + " AND " + end
- + " ORDER BY " + TRACK_COL_DATE + " ASC ", new String[]{String.valueOf(userId)});
-
- GPXFile gpxFile = null;
- long previousTime = 0;
- TrkSegment segment = null;
- Track track = null;
- if (query.moveToFirst()) {
- gpxFile = new GPXFile();
- gpxFile.userId = userId;
- do {
- long time = query.getLong(7);
- WptPt pt = new WptPt();
- pt.userId = query.getInt(0);
- pt.chatId = query.getLong(1);
- pt.lat = query.getDouble(2);
- pt.lon = query.getDouble(3);
- pt.ele = query.getDouble(4);
- pt.speed = query.getDouble(5);
- pt.hdop = query.getDouble(6);
- pt.time = time;
- long currentInterval = Math.abs(time - previousTime);
-
- if (track != null) {
- if (currentInterval < 30 * 60 * 1000) {
- // 30 minute - same segment
- segment.points.add(pt);
- } else {
- segment = new TrkSegment();
- segment.points.add(pt);
- track.segments.add(segment);
- }
- } else {
- track = new Track();
- segment = new TrkSegment();
- track.segments.add(segment);
- segment.points.add(pt);
-
- gpxFile.tracks.add(track);
- }
- previousTime = time;
- } while (query.moveToNext());
- }
- query.close();
- return gpxFile;
- }
-
- private void collectDBTracksForUsers(SQLiteDatabase db, ArrayList dataTracks, long start, long end, ArrayList ignoredUsersIds) {
- Cursor query = db.rawQuery("SELECT " + TRACK_COL_USER_ID + "," + TRACK_COL_CHAT_ID + ","
- + TRACK_COL_LAT + "," + TRACK_COL_LON + "," + TRACK_COL_ALTITUDE + "," + TRACK_COL_SPEED + ","
- + TRACK_COL_HDOP + "," + TRACK_COL_DATE + " FROM " + TRACK_NAME + " WHERE " + TRACK_COL_DATE
- + " BETWEEN " + start + " AND " + end + " ORDER BY " + TRACK_COL_USER_ID + " ASC, "
- + TRACK_COL_CHAT_ID + " ASC, " + TRACK_COL_DATE + " ASC ", null);
-
- long previousTime = 0;
- long previousChatId = 0;
- int previousUserId = 0;
- TrkSegment segment = null;
- Track track = null;
- GPXFile gpx = new GPXFile();
- if (query.moveToFirst()) {
- do {
- int userId = query.getInt(0);
- if (ignoredUsersIds.contains(userId)) {
- continue;
- }
- int chatId = query.getInt(1);
- long time = query.getLong(7);
- if (previousUserId != userId || previousChatId != chatId) {
- gpx = new GPXFile();
- gpx.chatId = chatId;
- gpx.userId = userId;
- previousTime = 0;
- track = null;
- segment = null;
- dataTracks.add(gpx);
- }
-
- WptPt pt = new WptPt();
- pt.userId = userId;
- pt.chatId = chatId;
- pt.lat = query.getDouble(2);
- pt.lon = query.getDouble(3);
- pt.ele = query.getDouble(4);
- pt.speed = query.getDouble(5);
- pt.hdop = query.getDouble(6);
- pt.time = time;
- long currentInterval = Math.abs(time - previousTime);
- if (track != null) {
- if (currentInterval < 30 * 60 * 1000) {
- // 30 minute - same segment
- segment.points.add(pt);
- } else {
- segment = new TrkSegment();
- segment.points.add(pt);
- track.segments.add(segment);
- }
- } else {
- track = new Track();
- segment = new TrkSegment();
- track.segments.add(segment);
- segment.points.add(pt);
-
- gpx.tracks.add(track);
- }
- previousTime = time;
- previousUserId = userId;
- previousChatId = chatId;
- } while (query.moveToNext());
- }
- query.close();
- }
-
- private static class SaveGPXTrackToFileTask extends AsyncTask> {
-
- private TelegramApplication app;
- private SaveGpxListener listener;
-
- private final GPXFile gpxFile;
- private File dir;
- private int userId;
-
- SaveGPXTrackToFileTask(TelegramApplication app, SaveGpxListener listener, GPXFile gpxFile, File dir, int userId) {
- this.gpxFile = gpxFile;
- this.listener = listener;
- this.app = app;
- this.dir = dir;
- this.userId = userId;
- }
-
- @Override
- protected List doInBackground(Void... params) {
- List warnings = new ArrayList();
- dir.mkdirs();
- if (dir.getParentFile().canWrite()) {
- if (dir.exists()) {
-
- // save file
- File fout = new File(dir, userId + ".gpx"); //$NON-NLS-1$
- if (!gpxFile.isEmpty()) {
- WptPt pt = gpxFile.findPointToShow();
-
- TdApi.User user = app.getTelegramHelper().getUser(pt.userId);
- String fileName;
- if (user != null) {
- fileName = TelegramUiHelper.INSTANCE.getUserName(user)
- + "_" + new SimpleDateFormat("yyyy-MM-dd_HH-mm_EEE", Locale.US).format(new Date(pt.time)); //$NON-NLS-1$
- } else {
- fileName = userId + "_" + new SimpleDateFormat("yyyy-MM-dd_HH-mm_EEE", Locale.US).format(new Date(pt.time)); //$NON-NLS-1$
- }
- fout = new File(dir, fileName + ".gpx"); //$NON-NLS-1$
- int ind = 1;
- while (fout.exists()) {
- fout = new File(dir, fileName + "_" + (++ind) + ".gpx"); //$NON-NLS-1$ //$NON-NLS-2$
- }
- }
- String warn = GPXUtilities.writeGpxFile(fout, gpxFile, app);
- if (warn != null) {
- warnings.add(warn);
- return warnings;
- }
- }
- }
-
- return warnings;
- }
-
- @Override
- protected void onPostExecute(List warnings) {
- if (listener != null) {
- if (warnings != null && warnings.isEmpty()) {
- listener.onSavingGpxFinish(gpxFile.path);
- } else {
- listener.onSavingGpxError(warnings);
- }
- }
- }
- }
-
-
- public interface SaveGpxListener {
-
- void onSavingGpxFinish(String path);
-
- void onSavingGpxError(List warnings);
- }
-}
\ No newline at end of file
diff --git a/OsmAnd-telegram/src/net/osmand/telegram/helpers/ShareLocationHelper.kt b/OsmAnd-telegram/src/net/osmand/telegram/helpers/ShareLocationHelper.kt
index e8040846ff..f7691710f6 100644
--- a/OsmAnd-telegram/src/net/osmand/telegram/helpers/ShareLocationHelper.kt
+++ b/OsmAnd-telegram/src/net/osmand/telegram/helpers/ShareLocationHelper.kt
@@ -3,6 +3,7 @@ package net.osmand.telegram.helpers
import net.osmand.Location
import net.osmand.PlatformUtil
import net.osmand.telegram.*
+import net.osmand.telegram.helpers.LocationMessages.LocationMessage
import net.osmand.telegram.notifications.TelegramNotification.NotificationType
import net.osmand.telegram.utils.AndroidNetworkUtils
import net.osmand.telegram.utils.BASE_URL
@@ -48,36 +49,9 @@ class ShareLocationHelper(private val app: TelegramApplication) {
lastLocation = location
if (location != null) {
- val chatsShareInfo = app.settings.getChatsShareInfo()
- if (chatsShareInfo.isNotEmpty()) {
- val latitude = location.latitude
- val longitude = location.longitude
- val user = app.telegramHelper.getCurrentUser()
- val sharingMode = app.settings.currentSharingMode
-
- if (user != null && sharingMode == user.id.toString()) {
- when (app.settings.shareTypeValue) {
- SHARE_TYPE_MAP -> app.telegramHelper.sendLiveLocationMessage(chatsShareInfo, latitude, longitude)
- SHARE_TYPE_TEXT -> app.telegramHelper.sendLiveLocationText(chatsShareInfo, location)
- SHARE_TYPE_MAP_AND_TEXT -> {
- app.telegramHelper.sendLiveLocationMessage(chatsShareInfo, latitude, longitude)
- app.telegramHelper.sendLiveLocationText(chatsShareInfo, location)
- }
- }
- } else if (sharingMode.isNotEmpty()) {
- val url = getDeviceSharingUrl(location,sharingMode)
- AndroidNetworkUtils.sendRequestAsync(app, url, null, "Send Location", false, false,
- object : AndroidNetworkUtils.OnRequestResultListener {
- override fun onResult(result: String?) {
- updateShareInfoSuccessfulSendTime(result, chatsShareInfo)
-
- val osmandBot = app.telegramHelper.getOsmandBot()
- if (osmandBot != null) {
- checkAndSendViaBotMessages(chatsShareInfo, TdApi.Location(latitude, longitude), osmandBot)
- }
- }
- })
- }
+ if (app.settings.getChatsShareInfo().isNotEmpty()) {
+ addNewLocationMessages(location, app.telegramHelper.getCurrentUserId())
+ shareMessages()
}
lastLocationMessageSentTime = System.currentTimeMillis()
}
@@ -158,25 +132,119 @@ class ShareLocationHelper(private val app: TelegramApplication) {
refreshNotification()
}
- private fun getDeviceSharingUrl(loc: Location, sharingMode: String): String {
- val url = "$BASE_URL/device/$sharingMode/send?lat=${loc.latitude}&lon=${loc.longitude}"
+ private fun addNewLocationMessages(location: Location, userId: Int) {
+ val chatsShareInfo = app.settings.getChatsShareInfo()
+ val latitude = location.latitude
+ val longitude = location.longitude
+ val isBot = app.settings.currentSharingMode != userId.toString()
+ val types = mutableListOf()
+
+ when (app.settings.shareTypeValue) {
+ SHARE_TYPE_MAP -> {
+ types.add(if (isBot) LocationMessage.TYPE_BOT_MAP else LocationMessage.TYPE_USER_MAP)
+ }
+ SHARE_TYPE_TEXT -> {
+ types.add(if (isBot) LocationMessage.TYPE_BOT_TEXT else LocationMessage.TYPE_USER_TEXT)
+ }
+ SHARE_TYPE_MAP_AND_TEXT -> {
+ types.add(if (isBot) LocationMessage.TYPE_BOT_MAP else LocationMessage.TYPE_USER_MAP)
+ types.add(if (isBot) LocationMessage.TYPE_BOT_TEXT else LocationMessage.TYPE_USER_TEXT)
+ }
+ }
+ chatsShareInfo.values.forEach { shareInfo ->
+ types.forEach {
+ val message = LocationMessage(userId, shareInfo.chatId, latitude, longitude, location.altitude, location.speed.toDouble(),
+ location.accuracy.toDouble(), location.bearing.toDouble(), location.time, it, LocationMessage.STATUS_PREPARING, shareInfo.currentMapMessageId)
+ app.locationMessages.addLocationMessage(message)
+ }
+ }
+ }
+
+ private fun shareMessages() {
+ var bufferedMessagesFull = false
+ app.locationMessages.getPreparedToShareMessages().forEach {
+ val shareChatInfo = app.settings.getChatsShareInfo()[it.chatId]
+ if (shareChatInfo != null) {
+ bufferedMessagesFull = shareChatInfo.bufferedMessages < 10
+ if (bufferedMessagesFull) {
+ when {
+ it.type == LocationMessage.TYPE_USER_TEXT -> {
+ shareChatInfo.bufferedMessages++
+ it.status = LocationMessage.STATUS_PENDING
+ app.telegramHelper.sendLiveLocationText(shareChatInfo, it)
+ }
+ it.type == LocationMessage.TYPE_USER_MAP -> {
+ shareChatInfo.bufferedMessages++
+ it.status = LocationMessage.STATUS_PENDING
+ app.telegramHelper.sendLiveLocationMap(shareChatInfo, it)
+ }
+ it.type == LocationMessage.TYPE_BOT_TEXT -> {
+ sendLocationToBot(it, app.settings.currentSharingMode, shareChatInfo, SHARE_TYPE_TEXT)
+ }
+ it.type == LocationMessage.TYPE_BOT_MAP -> {
+ sendLocationToBot(it, app.settings.currentSharingMode, shareChatInfo, SHARE_TYPE_MAP)
+ }
+ }
+ }
+ }
+ }
+ if (bufferedMessagesFull) {
+ checkNetworkType()
+ }
+ }
+
+ private fun checkNetworkType(){
+ if (app.isInternetConnectionAvailable) {
+ val networkType = when {
+ app.isWifiConnected -> TdApi.NetworkTypeWiFi()
+ app.isMobileConnected -> TdApi.NetworkTypeMobile()
+ else -> TdApi.NetworkTypeOther()
+ }
+ app.telegramHelper.networkChange(networkType)
+ }
+ }
+
+ private fun sendLocationToBot(locationMessage: LocationMessage, sharingMode: String, shareInfo: TelegramSettings.ShareChatInfo, shareType: String) {
+ if (app.isInternetConnectionAvailable) {
+ locationMessage.status = LocationMessage.STATUS_PENDING
+ val url = getDeviceSharingUrl(locationMessage, sharingMode)
+ AndroidNetworkUtils.sendRequestAsync(app, url, null, "Send Location", false, false,
+ object : AndroidNetworkUtils.OnRequestResultListener {
+ override fun onResult(result: String?) {
+ val chatsShareInfo = app.settings.getChatsShareInfo()
+ val success = checkResultAndUpdateShareInfoSuccessfulSendTime(result, chatsShareInfo)
+ val osmandBotId = app.telegramHelper.getOsmandBot()?.id ?: -1
+ val device = app.settings.getCurrentSharingDevice()
+
+ locationMessage.status = if (success) LocationMessage.STATUS_SENT else LocationMessage.STATUS_ERROR
+ if (success && shareInfo.shouldSendViaBotMessage && osmandBotId != -1 && device != null) {
+ app.telegramHelper.sendViaBotLocationMessage(osmandBotId, shareInfo, TdApi.Location(locationMessage.lat, locationMessage.lon), device, shareType)
+ shareInfo.shouldSendViaBotMessage = false
+ }
+ }
+ })
+ }
+ }
+
+ private fun getDeviceSharingUrl(loc: LocationMessage, sharingMode: String): String {
+ val url = "$BASE_URL/device/$sharingMode/send?lat=${loc.lat}&lon=${loc.lon}"
val builder = StringBuilder(url)
- if (loc.hasBearing() && loc.bearing != 0.0f) {
+ if (loc.bearing != 0.0) {
builder.append("&azi=${loc.bearing}")
}
- if (loc.hasSpeed() && loc.speed != 0.0f) {
+ if (loc.speed != 0.0) {
builder.append("&spd=${loc.speed}")
}
- if (loc.hasAltitude() && loc.altitude != 0.0) {
+ if (loc.altitude != 0.0) {
builder.append("&alt=${loc.altitude}")
}
- if (loc.hasAccuracy() && loc.accuracy != 0.0f) {
- builder.append("&hdop=${loc.accuracy}")
+ if (loc.hdop != 0.0) {
+ builder.append("&hdop=${loc.hdop}")
}
return builder.toString()
}
- private fun updateShareInfoSuccessfulSendTime(result: String?, chatsShareInfo: Map) {
+ private fun checkResultAndUpdateShareInfoSuccessfulSendTime(result: String?, chatsShareInfo: Map):Boolean {
if (result != null) {
try {
val jsonResult = JSONObject(result)
@@ -186,22 +254,12 @@ class ShareLocationHelper(private val app: TelegramApplication) {
chatsShareInfo.forEach { (_, shareInfo) ->
shareInfo.lastSuccessfulSendTimeMs = currentTime
}
+ return true
}
} catch (e: JSONException) {
}
}
- }
-
- private fun checkAndSendViaBotMessages(chatsShareInfo: Map, location: TdApi.Location, osmandBot: TdApi.User) {
- val device = app.settings.getCurrentSharingDevice()
- if (device != null) {
- chatsShareInfo.forEach { (_, shareInfo) ->
- if (shareInfo.shouldSendViaBotMessage) {
- app.telegramHelper.sendViaBotLocationMessage(osmandBot.id, shareInfo, location, device,app.settings.shareTypeValue)
- shareInfo.shouldSendViaBotMessage = false
- }
- }
- }
+ return false
}
private fun refreshNotification() {
@@ -216,4 +274,4 @@ class ShareLocationHelper(private val app: TelegramApplication) {
const val MIN_LOCATION_MESSAGE_LIVE_PERIOD_SEC = TelegramHelper.MIN_LOCATION_MESSAGE_LIVE_PERIOD_SEC - 1
const val MAX_LOCATION_MESSAGE_LIVE_PERIOD_SEC = TelegramHelper.MAX_LOCATION_MESSAGE_LIVE_PERIOD_SEC + 1
}
-}
+}
\ No newline at end of file
diff --git a/OsmAnd-telegram/src/net/osmand/telegram/helpers/ShowLocationHelper.kt b/OsmAnd-telegram/src/net/osmand/telegram/helpers/ShowLocationHelper.kt
index 9d52abdb37..ee3d12d90b 100644
--- a/OsmAnd-telegram/src/net/osmand/telegram/helpers/ShowLocationHelper.kt
+++ b/OsmAnd-telegram/src/net/osmand/telegram/helpers/ShowLocationHelper.kt
@@ -8,10 +8,11 @@ import net.osmand.aidl.map.ALatLon
import net.osmand.aidl.maplayer.point.AMapPoint
import net.osmand.telegram.R
import net.osmand.telegram.TelegramApplication
-import net.osmand.telegram.helpers.TelegramHelper.MessageOsmAndBotLocation
-import net.osmand.telegram.helpers.TelegramHelper.MessageUserTextLocation
import net.osmand.telegram.helpers.TelegramUiHelper.ListItem
import net.osmand.telegram.utils.AndroidUtils
+import net.osmand.telegram.utils.OsmandLocationUtils
+import net.osmand.telegram.utils.OsmandLocationUtils.MessageUserTextLocation
+import net.osmand.telegram.utils.OsmandLocationUtils.MessageOsmAndBotLocation
import org.drinkless.td.libcore.telegram.TdApi
import java.io.File
import java.util.concurrent.Executors
@@ -62,7 +63,7 @@ class ShowLocationHelper(private val app: TelegramApplication) {
execOsmandApi {
val messages = telegramHelper.getMessages()
for (message in messages) {
- val date = telegramHelper.getLastUpdatedTime(message)
+ val date = OsmandLocationUtils.getLastUpdatedTime(message)
val messageShowingTime = System.currentTimeMillis() / 1000 - date
if (messageShowingTime > app.settings.locHistoryTime) {
removeMapPoint(message.chatId, message)
@@ -78,7 +79,7 @@ class ShowLocationHelper(private val app: TelegramApplication) {
val chatId = message.chatId
val chatTitle = telegramHelper.getChat(message.chatId)?.title
val content = message.content
- val date = telegramHelper.getLastUpdatedTime(message)
+ val date = OsmandLocationUtils.getLastUpdatedTime(message)
val stale = System.currentTimeMillis() / 1000 - date > app.settings.staleLocTime
if (chatTitle != null && (content is TdApi.MessageLocation || (content is MessageUserTextLocation && content.isValid()))) {
var userName = ""
diff --git a/OsmAnd-telegram/src/net/osmand/telegram/helpers/TelegramHelper.kt b/OsmAnd-telegram/src/net/osmand/telegram/helpers/TelegramHelper.kt
index be9c2886a4..81f67c8421 100644
--- a/OsmAnd-telegram/src/net/osmand/telegram/helpers/TelegramHelper.kt
+++ b/OsmAnd-telegram/src/net/osmand/telegram/helpers/TelegramHelper.kt
@@ -3,15 +3,20 @@ package net.osmand.telegram.helpers
import android.text.TextUtils
import net.osmand.Location
import net.osmand.PlatformUtil
-import net.osmand.telegram.SHARE_TYPE_MAP
-import net.osmand.telegram.SHARE_TYPE_MAP_AND_TEXT
-import net.osmand.telegram.SHARE_TYPE_TEXT
-import net.osmand.telegram.TelegramSettings
+import net.osmand.telegram.*
import net.osmand.telegram.helpers.TelegramHelper.TelegramAuthenticationParameterType.*
import net.osmand.telegram.utils.BASE_SHARING_URL
import net.osmand.telegram.utils.GRAYSCALE_PHOTOS_DIR
import net.osmand.telegram.utils.GRAYSCALE_PHOTOS_EXT
-import net.osmand.util.GeoPointParserUtil
+import net.osmand.telegram.utils.OsmandLocationUtils
+import net.osmand.telegram.utils.OsmandLocationUtils.DEVICE_PREFIX
+import net.osmand.telegram.utils.OsmandLocationUtils.MessageOsmAndBotLocation
+import net.osmand.telegram.utils.OsmandLocationUtils.MessageUserTextLocation
+import net.osmand.telegram.utils.OsmandLocationUtils.USER_TEXT_LOCATION_TITLE
+import net.osmand.telegram.utils.OsmandLocationUtils.getLastUpdatedTime
+import net.osmand.telegram.utils.OsmandLocationUtils.parseOsmAndBotLocation
+import net.osmand.telegram.utils.OsmandLocationUtils.parseOsmAndBotLocationContent
+import net.osmand.telegram.utils.OsmandLocationUtils.parseTextLocation
import org.drinkless.td.libcore.telegram.Client
import org.drinkless.td.libcore.telegram.Client.ResultHandler
import org.drinkless.td.libcore.telegram.TdApi
@@ -36,32 +41,6 @@ class TelegramHelper private constructor() {
private const val IGNORED_ERROR_CODE = 406
private const val MESSAGE_CANNOT_BE_EDITED_ERROR_CODE = 5
- private const val DEVICE_PREFIX = "Device: "
- private const val LOCATION_PREFIX = "Location: "
- private const val LAST_LOCATION_PREFIX = "Last location: "
- private const val UPDATED_PREFIX = "Updated: "
- private const val USER_TEXT_LOCATION_TITLE = "\uD83D\uDDFA OsmAnd sharing:"
-
- private const val SHARING_LINK = "https://play.google.com/store/apps/details?id=net.osmand.telegram"
-
- private const val ALTITUDE_PREFIX = "Altitude: "
- private const val SPEED_PREFIX = "Speed: "
- private const val HDOP_PREFIX = "Horizontal precision: "
-
- private const val NOW = "now"
- private const val FEW_SECONDS_AGO = "few seconds ago"
- private const val SECONDS_AGO_SUFFIX = " seconds ago"
- private const val MINUTES_AGO_SUFFIX = " minutes ago"
- private const val HOURS_AGO_SUFFIX = " hours ago"
- private const val UTC_FORMAT_SUFFIX = " UTC"
-
- private val UTC_DATE_FORMAT = SimpleDateFormat("yyyy-MM-dd", Locale.US).apply {
- timeZone = TimeZone.getTimeZone("UTC")
- }
-
- private val UTC_TIME_FORMAT = SimpleDateFormat("HH:mm:ss", Locale.US).apply {
- timeZone = TimeZone.getTimeZone("UTC")
- }
// min and max values for the Telegram API
const val MIN_LOCATION_MESSAGE_LIVE_PERIOD_SEC = 61
const val MAX_LOCATION_MESSAGE_LIVE_PERIOD_SEC = 60 * 60 * 24 - 1 // one day
@@ -172,6 +151,8 @@ class TelegramHelper private constructor() {
fun getCurrentUser() = currentUser
+ fun getCurrentUserId() = currentUser?.id ?: -1
+
fun getUserMessage(user: TdApi.User) =
usersLocationMessages.values.firstOrNull { it.senderUserId == user.id }
@@ -216,15 +197,6 @@ class TelegramHelper private constructor() {
return chat.type is TdApi.ChatTypeSupergroup || chat.type is TdApi.ChatTypeBasicGroup
}
- fun getLastUpdatedTime(message: TdApi.Message): Int {
- val content = message.content
- return when (content) {
- is MessageOsmAndBotLocation -> content.lastUpdated
- is MessageUserTextLocation -> content.lastUpdated
- else -> Math.max(message.editDate, message.date)
- }
- }
-
fun isPrivateChat(chat: TdApi.Chat): Boolean = chat.type is TdApi.ChatTypePrivate
fun isSecretChat(chat: TdApi.Chat): Boolean = chat.type is TdApi.ChatTypeSecret
@@ -349,6 +321,12 @@ class TelegramHelper private constructor() {
}
}
+ fun networkChange(networkType: TdApi.NetworkType) {
+ client?.send(TdApi.SetNetworkType(networkType)) { obj ->
+ log.debug(obj)
+ }
+ }
+
fun isInit() = client != null && haveAuthorization
fun getUserPhotoPath(user: TdApi.User?) = when {
@@ -564,7 +542,7 @@ class TelegramHelper private constructor() {
resultArticles.forEach {
client?.send(TdApi.SendInlineQueryResultMessage(shareInfo.chatId, 0, true,
true, inlineQueryResults.inlineQueryId, it.id)) { obj ->
- handleTextLocationMessageUpdate(obj, shareInfo)
+ handleTextLocationMessageUpdate(obj, shareInfo, null)
}
}
}
@@ -728,7 +706,7 @@ class TelegramHelper private constructor() {
private fun addNewMessage(message: TdApi.Message) {
lastTelegramUpdateTime = Math.max(lastTelegramUpdateTime, Math.max(message.date, message.editDate))
if (message.isAppropriate()) {
- log.debug("addNewMessage: $message")
+ log.debug("addNewMessage: ${message.id}")
val fromBot = isOsmAndBot(message.senderUserId)
val viaBot = isOsmAndBot(message.viaBotUserId)
val oldContent = message.content
@@ -753,7 +731,7 @@ class TelegramHelper private constructor() {
usersLocationMessages[message.id] = message
}
incomingMessagesListeners.forEach {
- if (!hasNewerMessage || it is SavingTracksDbHelper) {
+ if (!hasNewerMessage || it is TelegramService) {
it.onReceiveChatLocationMessages(message.chatId, message)
}
}
@@ -779,7 +757,7 @@ class TelegramHelper private constructor() {
}
}
} else if (sameSender && isUserLocationMessage(message) && isUserLocationMessage(newMessage)
- && Math.max(newMessage.editDate, newMessage.date) > Math.max(message.editDate, message.date)) {
+ && Math.max(newMessage.editDate, newMessage.date) >= Math.max(message.editDate, message.date)) {
iterator.remove()
}
}
@@ -811,7 +789,7 @@ class TelegramHelper private constructor() {
if (shareInfo.currentMapMessageId != -1L && shareInfo.chatId != -1L) {
client?.send(
TdApi.EditMessageLiveLocation(shareInfo.chatId, shareInfo.currentMapMessageId, null, null)) { obj ->
- handleMapLocationMessageUpdate(obj, shareInfo)
+ handleMapLocationMessageUpdate(obj, shareInfo, null)
}
}
needRefreshActiveLiveLocationMessages = true
@@ -856,7 +834,7 @@ class TelegramHelper private constructor() {
private fun recreateLiveLocationMessage(
shareInfo: TelegramSettings.ShareChatInfo,
- content: TdApi.InputMessageContent
+ content: TdApi.InputMessageContent,locationMessage: LocationMessages.LocationMessage?
) {
if (shareInfo.chatId != -1L) {
val array = LongArray(1)
@@ -869,7 +847,7 @@ class TelegramHelper private constructor() {
log.debug("recreateLiveLocationMessage - ${array[0]}")
client?.send(TdApi.DeleteMessages(shareInfo.chatId, array, true)) { obj ->
when (obj.constructor) {
- TdApi.Ok.CONSTRUCTOR -> sendNewLiveLocationMessage(shareInfo, content)
+ TdApi.Ok.CONSTRUCTOR -> sendNewLiveLocationMessage(shareInfo, content,locationMessage)
TdApi.Error.CONSTRUCTOR -> {
val error = obj as TdApi.Error
if (error.code != IGNORED_ERROR_CODE) {
@@ -886,12 +864,12 @@ class TelegramHelper private constructor() {
needRefreshActiveLiveLocationMessages = true
}
- private fun sendNewLiveLocationMessage(shareInfo: TelegramSettings.ShareChatInfo, content: TdApi.InputMessageContent) {
+ private fun sendNewLiveLocationMessage(shareInfo: TelegramSettings.ShareChatInfo, content: TdApi.InputMessageContent, locationMessage: LocationMessages.LocationMessage?) {
needRefreshActiveLiveLocationMessages = true
log.debug("sendNewLiveLocationMessage")
client?.send(
TdApi.SendMessage(shareInfo.chatId, 0, false, true, null, content)) { obj ->
- handleMapLocationMessageUpdate(obj, shareInfo)
+ handleMapLocationMessageUpdate(obj, shareInfo, locationMessage)
}
}
@@ -913,52 +891,79 @@ class TelegramHelper private constructor() {
log.debug("sendLiveLocationImpl - $msgId pendingMapMessage ${shareInfo.pendingMapMessage}")
if (msgId != -1L) {
if (shareInfo.shouldDeletePreviousMapMessage) {
- recreateLiveLocationMessage(shareInfo, content)
+ recreateLiveLocationMessage(shareInfo, content, null)
shareInfo.shouldDeletePreviousMapMessage = false
shareInfo.currentMapMessageId = -1
} else {
log.debug("EditMessageLiveLocation - $msgId")
client?.send(
TdApi.EditMessageLiveLocation(chatId, msgId, null, location)) { obj ->
- handleMapLocationMessageUpdate(obj, shareInfo)
+ handleMapLocationMessageUpdate(obj, shareInfo, null)
}
}
} else if (!shareInfo.pendingMapMessage || shareInfo.pendingMapMessage && timeAfterLastSendMessage > SEND_NEW_MESSAGE_INTERVAL_SEC) {
- sendNewLiveLocationMessage(shareInfo, content)
+ sendNewLiveLocationMessage(shareInfo, content, null)
}
}
}
- fun sendLiveLocationText(chatsShareInfo: Map, location: Location) {
- chatsShareInfo.forEach { (chatId, shareInfo) ->
- if (shareInfo.getChatLiveMessageExpireTime() <= 0) {
- return@forEach
+ fun sendLiveLocationMap(shareInfo: TelegramSettings.ShareChatInfo, locationMessage: LocationMessages.LocationMessage) {
+ val location = TdApi.Location(locationMessage.lat, locationMessage.lon)
+ val livePeriod = if (shareInfo.currentMessageLimit > (shareInfo.start + MAX_LOCATION_MESSAGE_LIVE_PERIOD_SEC)) {
+ MAX_LOCATION_MESSAGE_LIVE_PERIOD_SEC
+ } else {
+ shareInfo.livePeriod.toInt()
}
- val msgId = shareInfo.currentTextMessageId
- if (msgId == -1L) {
- shareInfo.updateTextMessageId = 1
+ val content = TdApi.InputMessageLocation(location, livePeriod)
+ val msgId = shareInfo.currentMapMessageId
+ val timeAfterLastSendMessage = ((System.currentTimeMillis() / 1000) - shareInfo.lastSendMapMessageTime)
+ log.debug("sendLiveLocationImpl - $msgId pendingMapMessage ${shareInfo.pendingMapMessage}")
+ if (msgId != -1L) {
+ if (shareInfo.shouldDeletePreviousMapMessage) {
+ recreateLiveLocationMessage(shareInfo, content, locationMessage)
+ shareInfo.shouldDeletePreviousMapMessage = false
+ shareInfo.currentMapMessageId = -1
+ } else {
+ log.debug("EditMessageLiveLocation - $msgId")
+ client?.send(
+ TdApi.EditMessageLiveLocation(shareInfo.chatId, msgId, null, location)) { obj ->
+ handleMapLocationMessageUpdate(obj, shareInfo, locationMessage)
+ }
}
- val content = getTextMessageContent(shareInfo.updateTextMessageId, location)
- val timeAfterLastSendMessage = ((System.currentTimeMillis() / 1000) - shareInfo.lastSendTextMessageTime)
- log.debug("sendLiveLocationText - $msgId pendingMapMessage ${shareInfo.pendingTextMessage}")
- if (msgId != -1L) {
- if (shareInfo.shouldDeletePreviousTextMessage) {
- recreateLiveLocationMessage(shareInfo, content)
- shareInfo.shouldDeletePreviousTextMessage = false
- } else {
- client?.send(TdApi.EditMessageText(chatId, msgId, null, content)) { obj ->
- handleTextLocationMessageUpdate(obj, shareInfo)
- }
+ } else if (!shareInfo.pendingMapMessage || shareInfo.pendingMapMessage && timeAfterLastSendMessage > SEND_NEW_MESSAGE_INTERVAL_SEC) {
+ sendNewLiveLocationMessage(shareInfo, content, locationMessage)
+ }
+ }
+
+ fun sendLiveLocationText(shareInfo: TelegramSettings.ShareChatInfo, location: LocationMessages.LocationMessage) {
+ val msgId = shareInfo.currentTextMessageId
+ if (msgId == -1L) {
+ shareInfo.updateTextMessageId = 1
+ }
+ val content = OsmandLocationUtils.getTextMessageContent(shareInfo.updateTextMessageId, location)
+ val timeAfterLastSendMessage = ((System.currentTimeMillis() / 1000) - shareInfo.lastSendTextMessageTime)
+ log.debug("sendLiveLocationText - $msgId pendingMapMessage ${shareInfo.pendingTextMessage}")
+ if (msgId != -1L) {
+ if (shareInfo.shouldDeletePreviousTextMessage) {
+ recreateLiveLocationMessage(shareInfo, content, location)
+ shareInfo.shouldDeletePreviousTextMessage = false
+ } else {
+ client?.send(TdApi.EditMessageText(shareInfo.chatId, msgId, null, content)) { obj ->
+ handleTextLocationMessageUpdate(obj, shareInfo, location)
}
- } else if (!shareInfo.pendingTextMessage || shareInfo.pendingTextMessage && timeAfterLastSendMessage > SEND_NEW_MESSAGE_INTERVAL_SEC) {
- client?.send(TdApi.SendMessage(chatId, 0, false, false, null, content)) { obj ->
- handleTextLocationMessageUpdate(obj, shareInfo)
+ }
+ } else {
+ if (!shareInfo.pendingTextMessage) {
+ client?.send(TdApi.SendMessage(shareInfo.chatId, 0, false, false, null, content)) { obj ->
+ handleTextLocationMessageUpdate(obj, shareInfo, location)
}
+ } else if(timeAfterLastSendMessage > SEND_NEW_MESSAGE_INTERVAL_SEC){
+
}
}
}
- private fun handleMapLocationMessageUpdate(obj: TdApi.Object, shareInfo: TelegramSettings.ShareChatInfo) {
+ private fun handleMapLocationMessageUpdate(obj: TdApi.Object, shareInfo: TelegramSettings.ShareChatInfo, location: LocationMessages.LocationMessage?) {
when (obj.constructor) {
TdApi.Error.CONSTRUCTOR -> {
val error = obj as TdApi.Error
@@ -978,6 +983,7 @@ class TelegramHelper private constructor() {
obj.sendingState?.constructor == TdApi.MessageSendingStateFailed.CONSTRUCTOR -> {
shareInfo.hasSharingError = true
needRefreshActiveLiveLocationMessages = true
+ location?.status = LocationMessages.LocationMessage.STATUS_ERROR
outgoingMessagesListeners.forEach {
it.onSendLiveLocationError(-1, "Map location message ${obj.id} failed to send")
}
@@ -985,10 +991,14 @@ class TelegramHelper private constructor() {
obj.sendingState?.constructor == TdApi.MessageSendingStatePending.CONSTRUCTOR -> {
shareInfo.pendingMapMessage = true
shareInfo.lastSendMapMessageTime = obj.date
+ location?.status = LocationMessages.LocationMessage.STATUS_PENDING
log.debug("handleMapLocationMessageUpdate - MessageSendingStatePending")
}
else -> {
shareInfo.hasSharingError = false
+ shareInfo.bufferedMessages--
+ location?.messageId = obj.id
+ location?.status = LocationMessages.LocationMessage.STATUS_SENT
outgoingMessagesListeners.forEach {
it.onUpdateMessages(listOf(obj))
}
@@ -999,7 +1009,7 @@ class TelegramHelper private constructor() {
}
}
- private fun handleTextLocationMessageUpdate(obj: TdApi.Object, shareInfo: TelegramSettings.ShareChatInfo) {
+ private fun handleTextLocationMessageUpdate(obj: TdApi.Object, shareInfo: TelegramSettings.ShareChatInfo, location: LocationMessages.LocationMessage?) {
when (obj.constructor) {
TdApi.Error.CONSTRUCTOR -> {
val error = obj as TdApi.Error
@@ -1017,7 +1027,9 @@ class TelegramHelper private constructor() {
when {
obj.sendingState?.constructor == TdApi.MessageSendingStateFailed.CONSTRUCTOR -> {
shareInfo.hasSharingError = true
+ shareInfo.bufferedMessages--
needRefreshActiveLiveLocationMessages = true
+ location?.status = LocationMessages.LocationMessage.STATUS_ERROR
outgoingMessagesListeners.forEach {
it.onSendLiveLocationError(-1, "Text location message ${obj.id} failed to send")
}
@@ -1025,10 +1037,14 @@ class TelegramHelper private constructor() {
obj.sendingState?.constructor == TdApi.MessageSendingStatePending.CONSTRUCTOR -> {
shareInfo.pendingTextMessage = true
shareInfo.lastSendTextMessageTime = obj.date
+ location?.status = LocationMessages.LocationMessage.STATUS_PENDING
log.debug("handleTextLocationMessageUpdate - MessageSendingStatePending")
}
else -> {
shareInfo.hasSharingError = false
+ shareInfo.bufferedMessages--
+ location?.messageId = obj.id
+ location?.status = LocationMessages.LocationMessage.STATUS_SENT
outgoingMessagesListeners.forEach {
it.onUpdateMessages(listOf(obj))
}
@@ -1039,54 +1055,6 @@ class TelegramHelper private constructor() {
}
}
- private fun formatLocation(sig: Location): String {
- return String.format(Locale.US, "%.5f, %.5f", sig.latitude, sig.longitude)
- }
-
- private fun formatFullTime(ti: Long): String {
- val dt = Date(ti)
- return UTC_DATE_FORMAT.format(dt) + " " + UTC_TIME_FORMAT.format(dt) + " UTC"
- }
-
- private fun getTextMessageContent(updateId: Int, location: Location): TdApi.InputMessageText {
- val entities = mutableListOf()
- val builder = StringBuilder()
- val locationMessage = formatLocation(location)
-
- val firstSpace = USER_TEXT_LOCATION_TITLE.indexOf(' ')
- val secondSpace = USER_TEXT_LOCATION_TITLE.indexOf(' ', firstSpace + 1)
- entities.add(TdApi.TextEntity(builder.length + firstSpace + 1, secondSpace - firstSpace, TdApi.TextEntityTypeTextUrl(SHARING_LINK)))
- builder.append("$USER_TEXT_LOCATION_TITLE\n")
-
- entities.add(TdApi.TextEntity(builder.lastIndex, LOCATION_PREFIX.length, TdApi.TextEntityTypeBold()))
- builder.append(LOCATION_PREFIX)
-
- entities.add(TdApi.TextEntity(builder.length, locationMessage.length,
- TdApi.TextEntityTypeTextUrl("$BASE_SHARING_URL?lat=${location.latitude}&lon=${location.longitude}")))
- builder.append("$locationMessage\n")
-
- if (location.hasAltitude() && location.altitude != 0.0) {
- entities.add(TdApi.TextEntity(builder.lastIndex, ALTITUDE_PREFIX.length, TdApi.TextEntityTypeBold()))
- builder.append(String.format(Locale.US, "$ALTITUDE_PREFIX%.1f m\n", location.altitude))
- }
- if (location.hasSpeed() && location.speed > 0) {
- entities.add(TdApi.TextEntity(builder.lastIndex, SPEED_PREFIX.length, TdApi.TextEntityTypeBold()))
- builder.append(String.format(Locale.US, "$SPEED_PREFIX%.1f m/s\n", location.speed))
- }
- if (location.hasAccuracy() && location.accuracy != 0.0f && location.speed == 0.0f) {
- entities.add(TdApi.TextEntity(builder.lastIndex, HDOP_PREFIX.length, TdApi.TextEntityTypeBold()))
- builder.append(String.format(Locale.US, "$HDOP_PREFIX%d m\n", location.accuracy.toInt()))
- }
- if (updateId == 0) {
- builder.append(String.format("$UPDATED_PREFIX%s\n", formatFullTime(location.time)))
- } else {
- builder.append(String.format("$UPDATED_PREFIX%s (%d)\n", formatFullTime(location.time), updateId))
- }
- val textMessage = builder.toString().trim()
-
- return TdApi.InputMessageText(TdApi.FormattedText(textMessage, entities.toTypedArray()), true, true)
- }
-
fun logout(): Boolean {
return if (libraryLoaded) {
haveAuthorization = false
@@ -1215,188 +1183,6 @@ class TelegramHelper private constructor() {
}
}
- private fun parseOsmAndBotLocation(message: TdApi.Message): MessageOsmAndBotLocation {
- val messageLocation = message.content as TdApi.MessageLocation
- return MessageOsmAndBotLocation().apply {
- name = getOsmAndBotDeviceName(message)
- lat = messageLocation.location.latitude
- lon = messageLocation.location.longitude
- lastUpdated = getLastUpdatedTime(message)
- }
- }
-
- private fun parseOsmAndBotLocationContent(oldContent:MessageOsmAndBotLocation, content: TdApi.MessageContent): MessageOsmAndBotLocation {
- val messageLocation = content as TdApi.MessageLocation
- return MessageOsmAndBotLocation().apply {
- name = oldContent.name
- lat = messageLocation.location.latitude
- lon = messageLocation.location.longitude
- lastUpdated = (System.currentTimeMillis() / 1000).toInt()
- }
- }
-
- private fun parseTextLocation(text: TdApi.FormattedText, botLocation: Boolean = true): MessageLocation {
- val res = if (botLocation) MessageOsmAndBotLocation() else MessageUserTextLocation()
-
- var locationNA = false
- for (s in text.text.lines()) {
- when {
- s.startsWith(DEVICE_PREFIX) -> {
- if (res is MessageOsmAndBotLocation) {
- res.name = s.removePrefix(DEVICE_PREFIX)
- }
- }
- s.startsWith(LOCATION_PREFIX) || s.startsWith(LAST_LOCATION_PREFIX) -> {
- var locStr: String
- var parse = true
- if (s.startsWith(LAST_LOCATION_PREFIX)) {
- locStr = s.removePrefix(LAST_LOCATION_PREFIX)
- if (!locationNA) {
- parse = false
- }
- } else {
- locStr = s.removePrefix(LOCATION_PREFIX)
- if (locStr.trim() == "n/a") {
- locationNA = true
- parse = false
- }
- }
- if (parse) {
- try {
- val urlTextEntity = text.entities.firstOrNull { it.type is TdApi.TextEntityTypeTextUrl }
- if (urlTextEntity != null && urlTextEntity.offset == text.text.indexOf(locStr)) {
- val url = (urlTextEntity.type as TdApi.TextEntityTypeTextUrl).url
- val point: GeoPointParserUtil.GeoParsedPoint? = GeoPointParserUtil.parse(url)
- if (point != null) {
- res.lat = point.latitude
- res.lon = point.longitude
- }
- } else {
- val (latS, lonS) = locStr.split(" ")
- res.lat = latS.dropLast(1).toDouble()
- res.lon = lonS.toDouble()
-
- val timeIndex = locStr.indexOf("(")
- if (timeIndex != -1) {
- val updatedS = locStr.substring(timeIndex, locStr.length)
- res.lastUpdated = (parseTime(updatedS.removePrefix("(").removeSuffix(")")) / 1000).toInt()
- }
- }
- } catch (e: Exception) {
- e.printStackTrace()
- }
- }
- }
- s.startsWith(ALTITUDE_PREFIX) -> {
- val altStr = s.removePrefix(ALTITUDE_PREFIX)
- try {
- val alt = altStr.split(" ").first()
- res.altitude = alt.toDouble()
- } catch (e: Exception) {
- e.printStackTrace()
- }
- }
- s.startsWith(SPEED_PREFIX) -> {
- val altStr = s.removePrefix(SPEED_PREFIX)
- try {
- val alt = altStr.split(" ").first()
- res.speed = alt.toDouble()
- } catch (e: Exception) {
- e.printStackTrace()
- }
- }
- s.startsWith(HDOP_PREFIX) -> {
- val altStr = s.removePrefix(HDOP_PREFIX)
- try {
- val alt = altStr.split(" ").first()
- res.hdop = alt.toDouble()
- } catch (e: Exception) {
- e.printStackTrace()
- }
- }
- s.startsWith(UPDATED_PREFIX) -> {
- if (res.lastUpdated == 0) {
- val updatedStr = s.removePrefix(UPDATED_PREFIX)
- val endIndex = updatedStr.indexOf("(")
- val updatedS = updatedStr.substring(0, if (endIndex != -1) endIndex else updatedStr.length)
- val parsedTime = (parseTime(updatedS.trim()) / 1000).toInt()
- val currentTime = (System.currentTimeMillis() / 1000) - 1
- res.lastUpdated = if (parsedTime < currentTime) parsedTime else currentTime.toInt()
- }
- }
- }
- }
- return res
- }
-
- private fun parseTime(timeS: String): Long {
- try {
- when {
- timeS.endsWith(FEW_SECONDS_AGO) -> return System.currentTimeMillis() - 5000
-
- timeS.endsWith(SECONDS_AGO_SUFFIX) -> {
- val locStr = timeS.removeSuffix(SECONDS_AGO_SUFFIX)
- return System.currentTimeMillis() - locStr.toLong() * 1000
- }
- timeS.endsWith(MINUTES_AGO_SUFFIX) -> {
- val locStr = timeS.removeSuffix(MINUTES_AGO_SUFFIX)
- val minutes = locStr.toLong()
- return System.currentTimeMillis() - minutes * 60 * 1000
- }
- timeS.endsWith(HOURS_AGO_SUFFIX) -> {
- val locStr = timeS.removeSuffix(HOURS_AGO_SUFFIX)
- val hours = locStr.toLong()
- return (System.currentTimeMillis() - hours * 60 * 60 * 1000)
- }
- timeS.endsWith(UTC_FORMAT_SUFFIX) -> {
- val locStr = timeS.removeSuffix(UTC_FORMAT_SUFFIX)
- val (latS, lonS) = locStr.split(" ")
- val date = UTC_DATE_FORMAT.parse(latS)
- val time = UTC_TIME_FORMAT.parse(lonS)
- val res = date.time + time.time
- return res
- }
- }
- } catch (e: Exception) {
- e.printStackTrace()
- }
- return 0
- }
-
- abstract class MessageLocation : TdApi.MessageContent() {
-
- var lat: Double = Double.NaN
- internal set
- var lon: Double = Double.NaN
- internal set
- var lastUpdated: Int = 0
- internal set
- var speed: Double = 0.0
- internal set
- var altitude: Double = 0.0
- internal set
- var hdop: Double = 0.0
- internal set
-
- override fun getConstructor() = -1
-
- abstract fun isValid(): Boolean
- }
-
- class MessageOsmAndBotLocation : MessageLocation() {
-
- var name: String = ""
- internal set
-
- override fun isValid() = name != "" && lat != Double.NaN && lon != Double.NaN
- }
-
- class MessageUserTextLocation : MessageLocation() {
-
- override fun isValid() = lat != Double.NaN && lon != Double.NaN
-
- }
-
class OrderedChat internal constructor(internal val order: Long, internal val chatId: Long, internal val isChannel: Boolean) : Comparable {
override fun compareTo(other: OrderedChat): Int {
diff --git a/OsmAnd-telegram/src/net/osmand/telegram/helpers/TelegramUiHelper.kt b/OsmAnd-telegram/src/net/osmand/telegram/helpers/TelegramUiHelper.kt
index 2a4f1b1436..33153b5fa0 100644
--- a/OsmAnd-telegram/src/net/osmand/telegram/helpers/TelegramUiHelper.kt
+++ b/OsmAnd-telegram/src/net/osmand/telegram/helpers/TelegramUiHelper.kt
@@ -6,8 +6,9 @@ import android.widget.ImageView
import net.osmand.data.LatLon
import net.osmand.telegram.R
import net.osmand.telegram.TelegramApplication
-import net.osmand.telegram.helpers.TelegramHelper.MessageOsmAndBotLocation
-import net.osmand.telegram.helpers.TelegramHelper.MessageUserTextLocation
+import net.osmand.telegram.utils.OsmandLocationUtils
+import net.osmand.telegram.utils.OsmandLocationUtils.MessageUserTextLocation
+import net.osmand.telegram.utils.OsmandLocationUtils.MessageOsmAndBotLocation
import net.osmand.telegram.utils.GPXUtilities
import org.drinkless.td.libcore.telegram.TdApi
@@ -65,7 +66,7 @@ object TelegramUiHelper {
val user = helper.getUser(userId)
val message = messages.firstOrNull { it.viaBotUserId == 0 }
if (message != null) {
- res.lastUpdated = helper.getLastUpdatedTime(message)
+ res.lastUpdated = OsmandLocationUtils.getLastUpdatedTime(message)
val content = message.content
if (content is TdApi.MessageLocation) {
res.latLon = LatLon(content.location.latitude, content.location.longitude)
@@ -172,7 +173,7 @@ object TelegramUiHelper {
grayscalePhotoPath = helper.getUserGreyPhotoPath(user)
placeholderId = R.drawable.img_user_picture
userId = message.senderUserId
- lastUpdated = helper.getLastUpdatedTime(message)
+ lastUpdated = OsmandLocationUtils.getLastUpdatedTime(message)
}
}
@@ -225,7 +226,7 @@ object TelegramUiHelper {
userId = message.senderUserId
privateChat = helper.isPrivateChat(chat) || helper.isSecretChat(chat)
chatWithBot = helper.isBot(userId)
- lastUpdated = helper.getLastUpdatedTime(message)
+ lastUpdated = OsmandLocationUtils.getLastUpdatedTime(message)
}
}
diff --git a/OsmAnd-telegram/src/net/osmand/telegram/ui/LiveNowTabFragment.kt b/OsmAnd-telegram/src/net/osmand/telegram/ui/LiveNowTabFragment.kt
index 073c9633f2..3d99af0a8f 100644
--- a/OsmAnd-telegram/src/net/osmand/telegram/ui/LiveNowTabFragment.kt
+++ b/OsmAnd-telegram/src/net/osmand/telegram/ui/LiveNowTabFragment.kt
@@ -19,7 +19,6 @@ import net.osmand.telegram.TelegramApplication
import net.osmand.telegram.TelegramLocationProvider.TelegramCompassListener
import net.osmand.telegram.TelegramLocationProvider.TelegramLocationListener
import net.osmand.telegram.TelegramSettings
-import net.osmand.telegram.helpers.SavingTracksDbHelper
import net.osmand.telegram.helpers.TelegramHelper.*
import net.osmand.telegram.helpers.TelegramUiHelper
import net.osmand.telegram.helpers.TelegramUiHelper.ChatItem
diff --git a/OsmAnd-telegram/src/net/osmand/telegram/ui/MainActivity.kt b/OsmAnd-telegram/src/net/osmand/telegram/ui/MainActivity.kt
index 62d50ee90d..6e62c2576b 100644
--- a/OsmAnd-telegram/src/net/osmand/telegram/ui/MainActivity.kt
+++ b/OsmAnd-telegram/src/net/osmand/telegram/ui/MainActivity.kt
@@ -19,6 +19,7 @@ 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.OsmandAidlHelper
import net.osmand.telegram.helpers.TelegramHelper
import net.osmand.telegram.helpers.TelegramHelper.*
@@ -183,7 +184,7 @@ class MainActivity : AppCompatActivity(), TelegramListener, ActionButtonsListene
override fun onStop() {
super.onStop()
settings.save()
- app.messagesDbHelper.saveMessages()
+ app.locationMessages.saveMessages()
}
override fun onDestroy() {
@@ -291,6 +292,14 @@ class MainActivity : AppCompatActivity(), TelegramListener, ActionButtonsListene
if (!app.showLocationHelper.showingLocation && settings.hasAnyChatToShowOnMap()) {
app.showLocationHelper.startShowingLocation()
}
+ if (app.telegramService == null) {
+ messages.forEach {
+ val locationMessage = OsmandLocationUtils.parseMessage(it, telegramHelper, LocationMessages.LocationMessage.STATUS_SENT)
+ if (locationMessage != null) {
+ app.locationMessages.addLocationMessage(locationMessage)
+ }
+ }
+ }
}
override fun onDeleteChatLocationMessages(chatId: Long, messages: List) {}
@@ -341,7 +350,7 @@ class MainActivity : AppCompatActivity(), TelegramListener, ActionButtonsListene
fun logoutTelegram(silent: Boolean = false) {
if (telegramHelper.getTelegramAuthorizationState() == TelegramHelper.TelegramAuthorizationState.READY) {
if (app.isInternetConnectionAvailable) {
- app.messagesDbHelper.clearMessages()
+ app.locationMessages.clearMessages()
settings.clear()
telegramHelper.logout()
} else {
diff --git a/OsmAnd-telegram/src/net/osmand/telegram/ui/MyLocationTabFragment.kt b/OsmAnd-telegram/src/net/osmand/telegram/ui/MyLocationTabFragment.kt
index 149f6c7cc1..a10603c9b8 100644
--- a/OsmAnd-telegram/src/net/osmand/telegram/ui/MyLocationTabFragment.kt
+++ b/OsmAnd-telegram/src/net/osmand/telegram/ui/MyLocationTabFragment.kt
@@ -714,6 +714,18 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
OsmandFormatter.getFormattedDuration(context!!, expiresIn, true)
)})"
}
+ holder.gpsPointsCollected?.apply {
+ if (shareInfo != null) {
+ val all = app.locationMessages.getOutgoingMessagesToChat(shareInfo.chatId)
+ text = "${all.size}"
+ }
+ }
+ holder.gpsPointsSent?.apply {
+ if (shareInfo != null) {
+ val sent = app.locationMessages.getOutgoingMessagesToChatFromDate(shareInfo.chatId, shareInfo.start * 1000)
+ text = "${sent.size}"
+ }
+ }
}
}
@@ -751,10 +763,12 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
val stopSharingDescr: TextView? = view.findViewById(R.id.stop_in)
val stopSharingFirstPart: TextView? = view.findViewById(R.id.ending_in_first_part)
val stopSharingSecondPart: TextView? = view.findViewById(R.id.ending_in_second_part)
+ val gpsPointsCollected: TextView? = view.findViewById(R.id.gps_points_collected)
+ val gpsPointsSent: TextView? = view.findViewById(R.id.gps_points_sent)
}
}
interface ActionButtonsListener {
fun switchButtonsVisibility(visible: Boolean)
}
-}
+}
\ No newline at end of file
diff --git a/OsmAnd-telegram/src/net/osmand/telegram/ui/SetTimeDialogFragment.kt b/OsmAnd-telegram/src/net/osmand/telegram/ui/SetTimeDialogFragment.kt
index 48616165db..c3007c9217 100644
--- a/OsmAnd-telegram/src/net/osmand/telegram/ui/SetTimeDialogFragment.kt
+++ b/OsmAnd-telegram/src/net/osmand/telegram/ui/SetTimeDialogFragment.kt
@@ -21,6 +21,7 @@ import net.osmand.telegram.helpers.TelegramUiHelper
import net.osmand.telegram.ui.SetTimeDialogFragment.SetTimeListAdapter.ChatViewHolder
import net.osmand.telegram.utils.AndroidUtils
import net.osmand.telegram.utils.OsmandFormatter
+import net.osmand.telegram.utils.OsmandLocationUtils
import net.osmand.telegram.utils.UiUtils
import net.osmand.util.MapUtils
import org.drinkless.td.libcore.telegram.TdApi
@@ -328,7 +329,7 @@ class SetTimeDialogFragment : BaseDialogFragment(), TelegramLocationListener, Te
val message = telegramHelper.getChatMessages(itemId).firstOrNull()
val content = message?.content
if (message != null && content is TdApi.MessageLocation && (location != null && content.location != null)) {
- val lastUpdated = telegramHelper.getLastUpdatedTime(message)
+ val lastUpdated = OsmandLocationUtils.getLastUpdatedTime(message)
holder.description?.visibility = View.VISIBLE
holder.description?.text = OsmandFormatter.getListItemLiveTimeDescr(app, lastUpdated)
diff --git a/OsmAnd-telegram/src/net/osmand/telegram/ui/TimelineTabFragment.kt b/OsmAnd-telegram/src/net/osmand/telegram/ui/TimelineTabFragment.kt
index 608e9e5fde..708b430ce6 100644
--- a/OsmAnd-telegram/src/net/osmand/telegram/ui/TimelineTabFragment.kt
+++ b/OsmAnd-telegram/src/net/osmand/telegram/ui/TimelineTabFragment.kt
@@ -4,6 +4,7 @@ import android.app.DatePickerDialog
import android.graphics.drawable.Drawable
import android.os.Build
import android.os.Bundle
+import android.os.Handler
import android.support.annotation.DrawableRes
import android.support.v4.app.Fragment
import android.support.v7.widget.LinearLayoutManager
@@ -21,8 +22,8 @@ import net.osmand.telegram.helpers.TelegramUiHelper
import net.osmand.telegram.helpers.TelegramUiHelper.ListItem
import net.osmand.telegram.ui.TimelineTabFragment.LiveNowListAdapter.BaseViewHolder
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 java.util.*
@@ -45,6 +46,8 @@ class TimelineTabFragment : Fragment() {
private var start = 0L
private var end = 0L
+ private var updateEnable: Boolean = false
+
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
@@ -93,6 +96,17 @@ class TimelineTabFragment : Fragment() {
return mainView
}
+ override fun onResume() {
+ super.onResume()
+ updateEnable = true
+ startHandler()
+ }
+
+ override fun onPause() {
+ super.onPause()
+ updateEnable = false
+ }
+
private fun setupBtnTextColor(textView: TextView) {
textView.setTextColor(AndroidUtils.createPressedColorStateList(app, true, R.color.ctrl_active_light, R.color.ctrl_light))
}
@@ -162,32 +176,37 @@ class TimelineTabFragment : Fragment() {
return normal
}
+ private fun startHandler() {
+ val updateAdapter = Handler()
+ updateAdapter.postDelayed({
+ if (updateEnable) {
+ updateList()
+ startHandler()
+ }
+ }, ADAPTER_UPDATE_INTERVAL_MIL)
+ }
+
private fun updateList() {
val res = mutableListOf()
- val s = System.currentTimeMillis()
- log.debug("updateList $s")
val ignoredUsersIds = ArrayList()
val currentUserId = telegramHelper.getCurrentUser()?.id
if (currentUserId != null) {
- val currentUserGpx:GPXUtilities.GPXFile? = app.savingTracksDbHelper.collectRecordedDataForUser(currentUserId, 0, start, end)
- if (currentUserGpx != null) {
- TelegramUiHelper.gpxToChatItem(telegramHelper, currentUserGpx, true)?.also {
- res.add(it)
+ val locationMessages = app.locationMessages.collectRecordedDataForUser(currentUserId, 0, start, end)
+ OsmandLocationUtils.convertLocationMessagesToGpxFiles(locationMessages, false).forEach {
+ TelegramUiHelper.gpxToChatItem(telegramHelper, it, true)?.also { chatItem ->
+ res.add(chatItem)
}
}
ignoredUsersIds.add(currentUserId)
}
- val gpxFiles = app.savingTracksDbHelper.collectRecordedDataForUsers(start, end, ignoredUsersIds)
- val e = System.currentTimeMillis()
-
- gpxFiles.forEach {
+ val locationMessages = app.locationMessages.collectRecordedDataForUsers(start, end, ignoredUsersIds)
+ OsmandLocationUtils.convertLocationMessagesToGpxFiles(locationMessages).forEach {
TelegramUiHelper.gpxToChatItem(telegramHelper, it,false)?.also { chatItem ->
res.add(chatItem)
}
}
adapter.items = sortAdapterItems(res)
- log.debug("updateList $s dif: ${e - s}")
}
private fun sortAdapterItems(list: MutableList): MutableList {
@@ -269,4 +288,8 @@ class TimelineTabFragment : Fragment() {
val bottomDivider: View? = view.findViewById(R.id.bottom_divider)
}
}
+
+ companion object {
+ private const val ADAPTER_UPDATE_INTERVAL_MIL = 15 * 1000L // 15 sec
+ }
}
\ No newline at end of file
diff --git a/OsmAnd-telegram/src/net/osmand/telegram/ui/UserGpxInfoFragment.kt b/OsmAnd-telegram/src/net/osmand/telegram/ui/UserGpxInfoFragment.kt
index cbfa2e8f46..a01e4803c5 100644
--- a/OsmAnd-telegram/src/net/osmand/telegram/ui/UserGpxInfoFragment.kt
+++ b/OsmAnd-telegram/src/net/osmand/telegram/ui/UserGpxInfoFragment.kt
@@ -21,11 +21,11 @@ import net.osmand.PlatformUtil
import net.osmand.aidl.gpx.AGpxBitmap
import net.osmand.telegram.R
import net.osmand.telegram.helpers.OsmandAidlHelper
-import net.osmand.telegram.helpers.SavingTracksDbHelper
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.util.Algorithms
import java.io.File
import java.text.SimpleDateFormat
@@ -63,7 +63,6 @@ class UserGpxInfoFragment : BaseDialogFragment() {
readFromBundle(savedInstanceState ?: arguments)
val userId = gpxFile.userId
- val chatId = gpxFile.chatId
val user = app.telegramHelper.getUser(userId)
if (user != null) {
@@ -134,12 +133,13 @@ class UserGpxInfoFragment : BaseDialogFragment() {
openGpx(gpx.path)
} else {
saveCurrentGpxToFile(object :
- SavingTracksDbHelper.SaveGpxListener {
+ OsmandLocationUtils.SaveGpxListener {
+
override fun onSavingGpxFinish(path: String) {
openGpx(path)
}
- override fun onSavingGpxError(warnings: MutableList?) {
+ override fun onSavingGpxError(warnings: List?) {
Toast.makeText(app, warnings?.firstOrNull(), Toast.LENGTH_LONG).show()
}
})
@@ -156,12 +156,12 @@ class UserGpxInfoFragment : BaseDialogFragment() {
(activity as MainActivity).shareGpx(gpx.path)
} else {
saveCurrentGpxToFile(object :
- SavingTracksDbHelper.SaveGpxListener {
+ OsmandLocationUtils.SaveGpxListener {
override fun onSavingGpxFinish(path: String) {
(activity as MainActivity).shareGpx(path)
}
- override fun onSavingGpxError(warnings: MutableList?) {
+ override fun onSavingGpxError(warnings: List?) {
Toast.makeText(app, warnings?.firstOrNull(), Toast.LENGTH_LONG).show()
}
})
@@ -189,8 +189,10 @@ class UserGpxInfoFragment : BaseDialogFragment() {
}
}
- private fun saveCurrentGpxToFile(listener: SavingTracksDbHelper.SaveGpxListener) {
- app.savingTracksDbHelper.saveGpx(listener, app.getExternalFilesDir(null), gpxFile)
+ private fun saveCurrentGpxToFile(listener: OsmandLocationUtils.SaveGpxListener) {
+ if (!gpxFile.isEmpty) {
+ OsmandLocationUtils.saveGpx(app, listener, app.getExternalFilesDir(null)!!, gpxFile)
+ }
}
private fun readFromBundle(bundle: Bundle?) {
@@ -205,7 +207,14 @@ class UserGpxInfoFragment : BaseDialogFragment() {
}
private fun updateGpxInfo() {
- gpxFile = app.savingTracksDbHelper.collectRecordedDataForUser(gpxFile.userId, gpxFile.chatId, startCalendar.timeInMillis, endCalendar.timeInMillis)
+ gpxFile = OsmandLocationUtils.convertLocationMessagesToGpxFiles(
+ app.locationMessages.collectRecordedDataForUser(
+ gpxFile.userId,
+ gpxFile.chatId,
+ startCalendar.timeInMillis,
+ endCalendar.timeInMillis
+ )
+ ).first()
updateGPXStatisticRow()
updateDateAndTimeButtons()
updateGPXMap()
@@ -229,7 +238,7 @@ class UserGpxInfoFragment : BaseDialogFragment() {
private fun updateGPXMap() {
saveCurrentGpxToFile(object :
- SavingTracksDbHelper.SaveGpxListener {
+ OsmandLocationUtils.SaveGpxListener {
override fun onSavingGpxFinish(path: String) {
val mgr = activity?.getSystemService(Context.WINDOW_SERVICE)
if (mgr != null) {
@@ -242,7 +251,7 @@ class UserGpxInfoFragment : BaseDialogFragment() {
}
}
- override fun onSavingGpxError(warnings: MutableList?) {
+ override fun onSavingGpxError(warnings: List?) {
log.debug("onSavingGpxError ${warnings?.firstOrNull()}")
}
})
diff --git a/OsmAnd-telegram/src/net/osmand/telegram/utils/OsmandLocationUtils.kt b/OsmAnd-telegram/src/net/osmand/telegram/utils/OsmandLocationUtils.kt
new file mode 100644
index 0000000000..ef1cf80f00
--- /dev/null
+++ b/OsmAnd-telegram/src/net/osmand/telegram/utils/OsmandLocationUtils.kt
@@ -0,0 +1,474 @@
+package net.osmand.telegram.utils
+
+import android.os.AsyncTask
+import net.osmand.Location
+import net.osmand.telegram.TelegramApplication
+import net.osmand.telegram.helpers.LocationMessages
+import net.osmand.telegram.helpers.TelegramHelper
+import net.osmand.telegram.helpers.TelegramUiHelper
+import net.osmand.util.GeoPointParserUtil
+import org.drinkless.td.libcore.telegram.TdApi
+import java.io.File
+import java.text.SimpleDateFormat
+import java.util.*
+
+
+object OsmandLocationUtils {
+
+ const val DEVICE_PREFIX = "Device: "
+ const val LOCATION_PREFIX = "Location: "
+ const val LAST_LOCATION_PREFIX = "Last location: "
+ const val UPDATED_PREFIX = "Updated: "
+ const val USER_TEXT_LOCATION_TITLE = "\uD83D\uDDFA OsmAnd sharing:"
+
+ const val SHARING_LINK = "https://play.google.com/store/apps/details?id=net.osmand.telegram"
+
+ const val ALTITUDE_PREFIX = "Altitude: "
+ const val SPEED_PREFIX = "Speed: "
+ const val HDOP_PREFIX = "Horizontal precision: "
+
+ const val NOW = "now"
+ const val FEW_SECONDS_AGO = "few seconds ago"
+ const val SECONDS_AGO_SUFFIX = " seconds ago"
+ const val MINUTES_AGO_SUFFIX = " minutes ago"
+ const val HOURS_AGO_SUFFIX = " hours ago"
+ const val UTC_FORMAT_SUFFIX = " UTC"
+
+ val UTC_DATE_FORMAT = SimpleDateFormat("yyyy-MM-dd", Locale.US).apply {
+ timeZone = TimeZone.getTimeZone("UTC")
+ }
+
+ val UTC_TIME_FORMAT = SimpleDateFormat("HH:mm:ss", Locale.US).apply {
+ timeZone = TimeZone.getTimeZone("UTC")
+ }
+
+ fun getLastUpdatedTime(message: TdApi.Message): Int {
+ val content = message.content
+ return when (content) {
+ is MessageOsmAndBotLocation -> content.lastUpdated
+ is MessageUserTextLocation -> content.lastUpdated
+ else -> Math.max(message.editDate, message.date)
+ }
+ }
+
+ fun getOsmAndBotDeviceName(message: TdApi.Message): String {
+ var deviceName = ""
+ if (message.replyMarkup is TdApi.ReplyMarkupInlineKeyboard) {
+ val replyMarkup = message.replyMarkup as TdApi.ReplyMarkupInlineKeyboard
+ try {
+ deviceName = replyMarkup.rows[0][1].text.split("\\s".toRegex())[1]
+ } catch (e: Exception) {
+
+ }
+ }
+ return deviceName
+ }
+
+ fun parseOsmAndBotLocation(message: TdApi.Message): MessageOsmAndBotLocation {
+ val messageLocation = message.content as TdApi.MessageLocation
+ return MessageOsmAndBotLocation().apply {
+ name = getOsmAndBotDeviceName(message)
+ lat = messageLocation.location.latitude
+ lon = messageLocation.location.longitude
+ lastUpdated = getLastUpdatedTime(message)
+ }
+ }
+
+ fun parseMessage(message: TdApi.Message, helper: TelegramHelper, status: Int): LocationMessages.LocationMessage? {
+ var locationMessage: LocationMessages.LocationMessage? = null
+ val oldContent = message.content
+
+ val fromBot = helper.isOsmAndBot(message.senderUserId)
+ val viaBot = helper.isOsmAndBot(message.viaBotUserId)
+
+ var messageType: Int = -1
+ val parsedMessageContent =
+ if (oldContent is TdApi.MessageText) {
+ when {
+ oldContent.text.text.startsWith(DEVICE_PREFIX) -> {
+ messageType = 3
+ parseTextLocation(oldContent.text)
+ }
+ oldContent.text.text.startsWith(USER_TEXT_LOCATION_TITLE) -> {
+ messageType = 1
+ parseTextLocation(oldContent.text, false)
+ }
+ else -> null
+ }
+ } else if (oldContent is TdApi.MessageLocation && (fromBot || viaBot)) {
+ messageType = 2
+ parseOsmAndBotLocation(message)
+ } else if (oldContent is MessageLocation) {
+ messageType = 0
+ oldContent
+ } else {
+ null
+ }
+
+ if (parsedMessageContent != null) {
+ locationMessage = LocationMessages.LocationMessage(message.senderUserId, message.chatId, parsedMessageContent.lat,
+ parsedMessageContent.lon, parsedMessageContent.altitude, parsedMessageContent.speed, parsedMessageContent.hdop,
+ parsedMessageContent.bearing, parsedMessageContent.lastUpdated * 1000L, messageType, status, message.id)
+ }
+ return locationMessage
+ }
+
+ fun formatLocation(sig: Location): String {
+ return String.format(Locale.US, "%.5f, %.5f", sig.latitude, sig.longitude)
+ }
+
+ fun formatLocation(sig: LocationMessages.LocationMessage): String {
+ return String.format(Locale.US, "%.5f, %.5f", sig.lat, sig.lon)
+ }
+
+ fun formatFullTime(ti: Long): String {
+ val dt = Date(ti)
+ return UTC_DATE_FORMAT.format(dt) + " " + UTC_TIME_FORMAT.format(dt) + " UTC"
+ }
+
+ fun parseOsmAndBotLocationContent(oldContent: MessageOsmAndBotLocation, content: TdApi.MessageContent): MessageOsmAndBotLocation {
+ val messageLocation = content as TdApi.MessageLocation
+ return MessageOsmAndBotLocation().apply {
+ name = oldContent.name
+ lat = messageLocation.location.latitude
+ lon = messageLocation.location.longitude
+ lastUpdated = (System.currentTimeMillis() / 1000).toInt()
+ }
+ }
+
+ fun parseTextLocation(text: TdApi.FormattedText, botLocation: Boolean = true): MessageLocation {
+ val res = if (botLocation) MessageOsmAndBotLocation() else MessageUserTextLocation()
+
+ var locationNA = false
+ for (s in text.text.lines()) {
+ when {
+ s.startsWith(DEVICE_PREFIX) -> {
+ if (res is MessageOsmAndBotLocation) {
+ res.name = s.removePrefix(DEVICE_PREFIX)
+ }
+ }
+ s.startsWith(LOCATION_PREFIX) || s.startsWith(LAST_LOCATION_PREFIX) -> {
+ var locStr: String
+ var parse = true
+ if (s.startsWith(LAST_LOCATION_PREFIX)) {
+ locStr = s.removePrefix(LAST_LOCATION_PREFIX)
+ if (!locationNA) {
+ parse = false
+ }
+ } else {
+ locStr = s.removePrefix(LOCATION_PREFIX)
+ if (locStr.trim() == "n/a") {
+ locationNA = true
+ parse = false
+ }
+ }
+ if (parse) {
+ try {
+ val urlTextEntity =
+ text.entities.firstOrNull { it.type is TdApi.TextEntityTypeTextUrl }
+ if (urlTextEntity != null && urlTextEntity.offset == text.text.indexOf(
+ locStr
+ )
+ ) {
+ val url = (urlTextEntity.type as TdApi.TextEntityTypeTextUrl).url
+ val point: GeoPointParserUtil.GeoParsedPoint? =
+ GeoPointParserUtil.parse(url)
+ if (point != null) {
+ res.lat = point.latitude
+ res.lon = point.longitude
+ }
+ } else {
+ val (latS, lonS) = locStr.split(" ")
+ res.lat = latS.dropLast(1).toDouble()
+ res.lon = lonS.toDouble()
+
+ val timeIndex = locStr.indexOf("(")
+ if (timeIndex != -1) {
+ val updatedS = locStr.substring(timeIndex, locStr.length)
+ res.lastUpdated =
+ (parseTime(updatedS.removePrefix("(").removeSuffix(")")) / 1000).toInt()
+ }
+ }
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
+ }
+ }
+ s.startsWith(ALTITUDE_PREFIX) -> {
+ val altStr = s.removePrefix(ALTITUDE_PREFIX)
+ try {
+ val alt = altStr.split(" ").first()
+ res.altitude = alt.toDouble()
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
+ }
+ s.startsWith(SPEED_PREFIX) -> {
+ val altStr = s.removePrefix(SPEED_PREFIX)
+ try {
+ val alt = altStr.split(" ").first()
+ res.speed = alt.toDouble()
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
+ }
+ s.startsWith(HDOP_PREFIX) -> {
+ val altStr = s.removePrefix(HDOP_PREFIX)
+ try {
+ val alt = altStr.split(" ").first()
+ res.hdop = alt.toDouble()
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
+ }
+ s.startsWith(UPDATED_PREFIX) -> {
+ if (res.lastUpdated == 0) {
+ val updatedStr = s.removePrefix(UPDATED_PREFIX)
+ val endIndex = updatedStr.indexOf("(")
+ val updatedS = updatedStr.substring(
+ 0,
+ if (endIndex != -1) endIndex else updatedStr.length
+ )
+ val parsedTime = (parseTime(updatedS.trim()) / 1000).toInt()
+ val currentTime = (System.currentTimeMillis() / 1000) - 1
+ res.lastUpdated =
+ if (parsedTime < currentTime) parsedTime else currentTime.toInt()
+ }
+ }
+ }
+ }
+ return res
+ }
+
+ fun parseTime(timeS: String): Long {
+ try {
+ when {
+ timeS.endsWith(FEW_SECONDS_AGO) -> return System.currentTimeMillis() - 5000
+
+ timeS.endsWith(SECONDS_AGO_SUFFIX) -> {
+ val locStr = timeS.removeSuffix(SECONDS_AGO_SUFFIX)
+ return System.currentTimeMillis() - locStr.toLong() * 1000
+ }
+ timeS.endsWith(MINUTES_AGO_SUFFIX) -> {
+ val locStr = timeS.removeSuffix(MINUTES_AGO_SUFFIX)
+ val minutes = locStr.toLong()
+ return System.currentTimeMillis() - minutes * 60 * 1000
+ }
+ timeS.endsWith(HOURS_AGO_SUFFIX) -> {
+ val locStr = timeS.removeSuffix(HOURS_AGO_SUFFIX)
+ val hours = locStr.toLong()
+ return (System.currentTimeMillis() - hours * 60 * 60 * 1000)
+ }
+ timeS.endsWith(UTC_FORMAT_SUFFIX) -> {
+ val locStr = timeS.removeSuffix(UTC_FORMAT_SUFFIX)
+ val (latS, lonS) = locStr.split(" ")
+ val date = UTC_DATE_FORMAT.parse(latS)
+ val time = UTC_TIME_FORMAT.parse(lonS)
+ val res = date.time + time.time
+ return res
+ }
+ }
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
+ return 0
+ }
+
+ fun getTextMessageContent(updateId: Int, location: LocationMessages.LocationMessage): TdApi.InputMessageText {
+ val entities = mutableListOf()
+ val builder = StringBuilder()
+ val locationMessage = formatLocation(location)
+
+ val firstSpace = USER_TEXT_LOCATION_TITLE.indexOf(' ')
+ val secondSpace = USER_TEXT_LOCATION_TITLE.indexOf(' ', firstSpace + 1)
+ entities.add(TdApi.TextEntity(builder.length + firstSpace + 1, secondSpace - firstSpace, TdApi.TextEntityTypeTextUrl(SHARING_LINK)))
+ builder.append("$USER_TEXT_LOCATION_TITLE\n")
+
+ entities.add(TdApi.TextEntity(builder.lastIndex, LOCATION_PREFIX.length, TdApi.TextEntityTypeBold()))
+ builder.append(LOCATION_PREFIX)
+
+ entities.add(TdApi.TextEntity(builder.length, locationMessage.length,
+ TdApi.TextEntityTypeTextUrl("$BASE_SHARING_URL?lat=${location.lat}&lon=${location.lon}")))
+ builder.append("$locationMessage\n")
+
+ if (location.altitude != 0.0) {
+ entities.add(TdApi.TextEntity(builder.lastIndex, ALTITUDE_PREFIX.length, TdApi.TextEntityTypeBold()))
+ builder.append(String.format(Locale.US, "$ALTITUDE_PREFIX%.1f m\n", location.altitude))
+ }
+ if (location.speed > 0) {
+ entities.add(TdApi.TextEntity(builder.lastIndex, SPEED_PREFIX.length, TdApi.TextEntityTypeBold()))
+ builder.append(String.format(Locale.US, "$SPEED_PREFIX%.1f m/s\n", location.speed))
+ }
+ if (location.hdop != 0.0 && location.speed == 0.0) {
+ entities.add(TdApi.TextEntity(builder.lastIndex, HDOP_PREFIX.length, TdApi.TextEntityTypeBold()))
+ builder.append(String.format(Locale.US, "$HDOP_PREFIX%d m\n", location.hdop.toInt()))
+ }
+ if (updateId == 0) {
+ builder.append(String.format("$UPDATED_PREFIX%s\n", formatFullTime(location.date)))
+ } else {
+ builder.append(String.format("$UPDATED_PREFIX%s (%d)\n", formatFullTime(location.date), updateId))
+ }
+ val textMessage = builder.toString().trim()
+
+ return TdApi.InputMessageText(TdApi.FormattedText(textMessage, entities.toTypedArray()), true, true)
+ }
+
+ fun convertLocationMessagesToGpxFiles(items: List, newGpxPerChat: Boolean = true): List {
+ val dataTracks = ArrayList()
+
+ var previousTime: Long = -1
+ var previousChatId: Long = -1
+ var previousUserId = -1
+ var segment: GPXUtilities.TrkSegment? = null
+ var track: GPXUtilities.Track? = null
+ var gpx: GPXUtilities.GPXFile? = null
+
+ items.forEach {
+ val userId = it.userId
+ val chatId = it.chatId
+ val time = it.date
+ if (previousUserId != userId || (newGpxPerChat && previousChatId != chatId)) {
+ gpx = GPXUtilities.GPXFile()
+ gpx!!.chatId = chatId
+ gpx!!.userId = userId
+ previousTime = 0
+ track = null
+ segment = null
+ dataTracks.add(gpx!!)
+ }
+ val pt = GPXUtilities.WptPt()
+ pt.userId = userId
+ pt.chatId = chatId
+ pt.lat = it.lat
+ pt.lon = it.lon
+ pt.ele = it.altitude
+ pt.speed = it.speed
+ pt.hdop = it.hdop
+ pt.time = time
+ val currentInterval = Math.abs(time - previousTime)
+ if (track != null) {
+ if (currentInterval < 30 * 60 * 1000) {
+ // 30 minute - same segment
+ segment!!.points.add(pt)
+ } else {
+ segment = GPXUtilities.TrkSegment()
+ segment!!.points.add(pt)
+ track!!.segments.add(segment)
+ }
+ } else {
+ track = GPXUtilities.Track()
+ segment = GPXUtilities.TrkSegment()
+ track!!.segments.add(segment)
+ segment!!.points.add(pt)
+
+ gpx!!.tracks.add(track)
+ }
+ previousTime = time
+ previousUserId = userId
+ previousChatId = chatId
+ }
+
+ return dataTracks
+ }
+
+ fun saveGpx(app: TelegramApplication, listener: SaveGpxListener, dir: File, gpxFile: GPXUtilities.GPXFile) {
+ if (!gpxFile.isEmpty) {
+ val task = SaveGPXTrackToFileTask(app, listener, gpxFile, dir, 0)
+ task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR)
+ }
+ }
+
+ abstract class MessageLocation : TdApi.MessageContent() {
+
+ var lat: Double = Double.NaN
+ internal set
+ var lon: Double = Double.NaN
+ internal set
+ var lastUpdated: Int = 0
+ internal set
+ var speed: Double = 0.0
+ internal set
+ var altitude: Double = 0.0
+ internal set
+ var hdop: Double = 0.0
+ internal set
+ var bearing: Double = 0.0
+ internal set
+
+ override fun getConstructor() = -1
+
+ abstract fun isValid(): Boolean
+ }
+
+ class MessageOsmAndBotLocation : MessageLocation() {
+
+ var name: String = ""
+ internal set
+
+ override fun isValid() = name != "" && lat != Double.NaN && lon != Double.NaN
+ }
+
+ class MessageUserTextLocation : MessageLocation() {
+
+ override fun isValid() = lat != Double.NaN && lon != Double.NaN
+
+ }
+
+ private class SaveGPXTrackToFileTask internal constructor(
+ private val app: TelegramApplication, private val listener: SaveGpxListener?,
+ private val gpxFile: GPXUtilities.GPXFile, private val dir: File, private val userId: Int
+ ) :
+ AsyncTask>() {
+
+ override fun doInBackground(vararg params: Void): List {
+ val warnings = ArrayList()
+ dir.mkdirs()
+ if (dir.parentFile.canWrite()) {
+ if (dir.exists()) {
+ // save file
+ var fout = File(dir, "$userId.gpx")
+ if (!gpxFile.isEmpty) {
+ val pt = gpxFile.findPointToShow()
+
+ val user = app.telegramHelper.getUser(pt!!.userId)
+ val fileName: String
+ fileName = if (user != null) {
+ (TelegramUiHelper.getUserName(user) + "_" + SimpleDateFormat("yyyy-MM-dd_HH-mm_EEE", Locale.US).format(Date(pt.time)))
+ } else {
+ 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) {
+ warnings.add(warn)
+ return warnings
+ }
+ }
+ }
+
+ return warnings
+ }
+
+ override fun onPostExecute(warnings: List?) {
+ if (listener != null) {
+ if (warnings != null && warnings.isEmpty()) {
+ listener.onSavingGpxFinish(gpxFile.path)
+ } else {
+ listener.onSavingGpxError(warnings)
+ }
+ }
+ }
+ }
+
+ interface SaveGpxListener {
+
+ fun onSavingGpxFinish(path: String)
+
+ fun onSavingGpxError(warnings: List?)
+ }
+}
\ No newline at end of file