Merge pull request #7283 from osmandapp/TrackerLiveTrack
Live track updates second part
This commit is contained in:
commit
e66615b32d
11 changed files with 214 additions and 1884 deletions
|
@ -2,8 +2,6 @@ package net.osmand.util;
|
||||||
|
|
||||||
import net.osmand.IProgress;
|
import net.osmand.IProgress;
|
||||||
import net.osmand.PlatformUtil;
|
import net.osmand.PlatformUtil;
|
||||||
import net.osmand.router.GeneralRouter;
|
|
||||||
import net.osmand.router.RoutingConfiguration;
|
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.xmlpull.v1.XmlPullParser;
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
|
@ -31,7 +29,6 @@ import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.Stack;
|
|
||||||
import java.util.zip.GZIPInputStream;
|
import java.util.zip.GZIPInputStream;
|
||||||
|
|
||||||
|
|
||||||
|
@ -370,6 +367,14 @@ public class Algorithms {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void createParentDirsForFile(File file) {
|
||||||
|
if (file != null && !file.exists()) {
|
||||||
|
File parent = file.getParentFile();
|
||||||
|
if (parent != null && !parent.exists()) {
|
||||||
|
parent.mkdirs();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("TryFinallyCanBeTryWithResources")
|
@SuppressWarnings("TryFinallyCanBeTryWithResources")
|
||||||
public static void fileCopy(File src, File dst) throws IOException {
|
public static void fileCopy(File src, File dst) throws IOException {
|
||||||
|
|
|
@ -21,6 +21,7 @@ import org.drinkless.td.libcore.telegram.TdApi
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
private const val UPDATE_LIVE_MESSAGES_INTERVAL_MS = 10000L // 10 sec
|
private const val UPDATE_LIVE_MESSAGES_INTERVAL_MS = 10000L // 10 sec
|
||||||
|
private const val UPDATE_LIVE_TRACKS_INTERVAL_MS = 30000L // 30 sec
|
||||||
|
|
||||||
class TelegramService : Service(), LocationListener, TelegramIncomingMessagesListener,
|
class TelegramService : Service(), LocationListener, TelegramIncomingMessagesListener,
|
||||||
TelegramOutgoingMessagesListener {
|
TelegramOutgoingMessagesListener {
|
||||||
|
@ -32,6 +33,9 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
|
||||||
private var updateShareInfoHandler: Handler? = null
|
private var updateShareInfoHandler: Handler? = null
|
||||||
private var mHandlerThread = HandlerThread("SharingServiceThread")
|
private var mHandlerThread = HandlerThread("SharingServiceThread")
|
||||||
|
|
||||||
|
private var updateTracksHandler: Handler? = null
|
||||||
|
private var tracksHandlerThread = HandlerThread("TracksUpdateServiceThread")
|
||||||
|
|
||||||
var handler: Handler? = null
|
var handler: Handler? = null
|
||||||
private set
|
private set
|
||||||
var usedBy = 0
|
var usedBy = 0
|
||||||
|
@ -53,7 +57,9 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
mHandlerThread.start()
|
mHandlerThread.start()
|
||||||
|
tracksHandlerThread.start()
|
||||||
updateShareInfoHandler = Handler(mHandlerThread.looper)
|
updateShareInfoHandler = Handler(mHandlerThread.looper)
|
||||||
|
updateTracksHandler = Handler(tracksHandlerThread.looper)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBind(intent: Intent): IBinder? {
|
override fun onBind(intent: Intent): IBinder? {
|
||||||
|
@ -103,6 +109,7 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
|
||||||
}
|
}
|
||||||
if (isUsedByUsersLocations(usedBy)) {
|
if (isUsedByUsersLocations(usedBy)) {
|
||||||
app.telegramHelper.startLiveMessagesUpdates(app.settings.sendMyLocInterval)
|
app.telegramHelper.startLiveMessagesUpdates(app.settings.sendMyLocInterval)
|
||||||
|
startTracksUpdates()
|
||||||
}
|
}
|
||||||
|
|
||||||
val locationNotification = app.notificationHelper.locationNotification
|
val locationNotification = app.notificationHelper.locationNotification
|
||||||
|
@ -130,6 +137,7 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
|
||||||
app.telegramHelper.removeOutgoingMessagesListener(this)
|
app.telegramHelper.removeOutgoingMessagesListener(this)
|
||||||
app.settings.save()
|
app.settings.save()
|
||||||
app.telegramService = null
|
app.telegramService = null
|
||||||
|
tracksHandlerThread.quit()
|
||||||
mHandlerThread.quit()
|
mHandlerThread.quit()
|
||||||
|
|
||||||
usedBy = 0
|
usedBy = 0
|
||||||
|
@ -191,6 +199,17 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
|
||||||
}, UPDATE_LIVE_MESSAGES_INTERVAL_MS)
|
}, UPDATE_LIVE_MESSAGES_INTERVAL_MS)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun startTracksUpdates() {
|
||||||
|
updateTracksHandler?.postDelayed({
|
||||||
|
if (isUsedByUsersLocations(usedBy)) {
|
||||||
|
if (app().settings.hasAnyLiveTracksToShowOnMap()) {
|
||||||
|
app().showLocationHelper.startUpdateTracksTask()
|
||||||
|
}
|
||||||
|
startTracksUpdates()
|
||||||
|
}
|
||||||
|
}, UPDATE_LIVE_TRACKS_INTERVAL_MS)
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressLint("MissingPermission")
|
@SuppressLint("MissingPermission")
|
||||||
private fun getFirstTimeRunDefaultLocation(): net.osmand.Location? {
|
private fun getFirstTimeRunDefaultLocation(): net.osmand.Location? {
|
||||||
val app = app()
|
val app = app()
|
||||||
|
|
|
@ -164,6 +164,19 @@ class TelegramSettings(private val app: TelegramApplication) {
|
||||||
|
|
||||||
fun hasAnyChatToShowOnMap() = !hiddenOnMapChats.containsAll(getLiveNowChats())
|
fun hasAnyChatToShowOnMap() = !hiddenOnMapChats.containsAll(getLiveNowChats())
|
||||||
|
|
||||||
|
fun hasAnyLiveTracksToShowOnMap(): Boolean {
|
||||||
|
val time = System.currentTimeMillis() - locHistoryTime * 1000
|
||||||
|
val locations = app.locationMessages.getLastLocationMessagesSinceTime(time)
|
||||||
|
locations.forEach { loc ->
|
||||||
|
if (liveTracksInfo.any { it.userId == loc.userId && it.chatId == loc.chatId && it.deviceName == loc.deviceName }) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getLiveTracksInfo() = liveTracksInfo
|
||||||
|
|
||||||
fun isShowingChatOnMap(chatId: Long) = !hiddenOnMapChats.contains(chatId)
|
fun isShowingChatOnMap(chatId: Long) = !hiddenOnMapChats.contains(chatId)
|
||||||
|
|
||||||
fun isLiveTrackEnabled(userId: Int, chatId: Long, deviceName: String) =
|
fun isLiveTrackEnabled(userId: Int, chatId: Long, deviceName: String) =
|
||||||
|
|
|
@ -79,6 +79,8 @@ class LocationMessages(val app: TelegramApplication) {
|
||||||
fun getLastLocationInfoForUserInChat(userId: Int, chatId: Long, deviceName: String) =
|
fun getLastLocationInfoForUserInChat(userId: Int, chatId: Long, deviceName: String) =
|
||||||
lastLocationPoints.sortedByDescending { it.time }.firstOrNull { it.userId == userId && it.chatId == chatId && it.deviceName == deviceName }
|
lastLocationPoints.sortedByDescending { it.time }.firstOrNull { it.userId == userId && it.chatId == chatId && it.deviceName == deviceName }
|
||||||
|
|
||||||
|
fun getLastLocationMessagesSinceTime(time: Long) = lastLocationPoints.filter { it.time > time }
|
||||||
|
|
||||||
fun addBufferedMessage(message: BufferMessage) {
|
fun addBufferedMessage(message: BufferMessage) {
|
||||||
log.debug("addBufferedMessage $message")
|
log.debug("addBufferedMessage $message")
|
||||||
val messages = mutableListOf(*this.bufferedMessages.toTypedArray())
|
val messages = mutableListOf(*this.bufferedMessages.toTypedArray())
|
||||||
|
|
|
@ -211,6 +211,25 @@ class OsmandAidlHelper(private val app: TelegramApplication) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get list of all imported GPX files.
|
||||||
|
*
|
||||||
|
* @return list of imported gpx files.
|
||||||
|
*/
|
||||||
|
val importedGpxFiles: List<AGpxFile>?
|
||||||
|
get() {
|
||||||
|
if (mIOsmAndAidlInterface != null) {
|
||||||
|
try {
|
||||||
|
val files = mutableListOf<AGpxFile>()
|
||||||
|
mIOsmAndAidlInterface!!.getImportedGpx(files)
|
||||||
|
return files
|
||||||
|
} catch (e: RemoteException) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
connectOsmand()
|
connectOsmand()
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,9 @@ import android.content.Intent
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.os.AsyncTask
|
import android.os.AsyncTask
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
|
import net.osmand.GPXUtilities
|
||||||
|
import net.osmand.PlatformUtil
|
||||||
|
import net.osmand.aidl.gpx.AGpxFile
|
||||||
import net.osmand.aidl.map.ALatLon
|
import net.osmand.aidl.map.ALatLon
|
||||||
import net.osmand.aidl.maplayer.point.AMapPoint
|
import net.osmand.aidl.maplayer.point.AMapPoint
|
||||||
import net.osmand.aidl.mapmarker.AMapMarker
|
import net.osmand.aidl.mapmarker.AMapMarker
|
||||||
|
@ -24,6 +27,8 @@ import java.util.concurrent.Executors
|
||||||
|
|
||||||
class ShowLocationHelper(private val app: TelegramApplication) {
|
class ShowLocationHelper(private val app: TelegramApplication) {
|
||||||
|
|
||||||
|
private val log = PlatformUtil.getLog(ShowLocationHelper::class.java)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val MAP_LAYER_ID = "telegram_layer"
|
const val MAP_LAYER_ID = "telegram_layer"
|
||||||
|
|
||||||
|
@ -32,11 +37,14 @@ class ShowLocationHelper(private val app: TelegramApplication) {
|
||||||
const val MAP_CONTEXT_MENU_BUTTON_ID = 1
|
const val MAP_CONTEXT_MENU_BUTTON_ID = 1
|
||||||
const val MAP_CONTEXT_MENU_BUTTONS_PARAMS_ID = "DIRECTION"
|
const val MAP_CONTEXT_MENU_BUTTONS_PARAMS_ID = "DIRECTION"
|
||||||
const val DIRECTION_ICON_ID = "ic_action_start_navigation"
|
const val DIRECTION_ICON_ID = "ic_action_start_navigation"
|
||||||
|
|
||||||
|
const val LIVE_TRACKS_DIR = "livetracks"
|
||||||
}
|
}
|
||||||
|
|
||||||
private val telegramHelper = app.telegramHelper
|
private val telegramHelper = app.telegramHelper
|
||||||
private val osmandAidlHelper = app.osmandAidlHelper
|
private val osmandAidlHelper = app.osmandAidlHelper
|
||||||
private val executor = Executors.newSingleThreadExecutor()
|
private val executor = Executors.newSingleThreadExecutor()
|
||||||
|
private val liveTracksExecutor = Executors.newSingleThreadExecutor()
|
||||||
|
|
||||||
private val points = ConcurrentHashMap<String, TdApi.Message>()
|
private val points = ConcurrentHashMap<String, TdApi.Message>()
|
||||||
private val markers = ConcurrentHashMap<String, AMapMarker>()
|
private val markers = ConcurrentHashMap<String, AMapMarker>()
|
||||||
|
@ -246,6 +254,72 @@ class ShowLocationHelper(private val app: TelegramApplication) {
|
||||||
osmandAidlHelper.removeContextMenuButtons(MAP_CONTEXT_MENU_BUTTONS_PARAMS_ID)
|
osmandAidlHelper.removeContextMenuButtons(MAP_CONTEXT_MENU_BUTTONS_PARAMS_ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun updateTracksOnMap() {
|
||||||
|
val startTime = System.currentTimeMillis()
|
||||||
|
osmandAidlHelper.execOsmandApi {
|
||||||
|
val gpxFiles = getLiveGpxFiles()
|
||||||
|
if (gpxFiles.isEmpty()) {
|
||||||
|
return@execOsmandApi
|
||||||
|
}
|
||||||
|
|
||||||
|
val importedGpxFiles = osmandAidlHelper.importedGpxFiles
|
||||||
|
gpxFiles.forEach {
|
||||||
|
if (!isGpxAlreadyImported(importedGpxFiles, it)) {
|
||||||
|
val listener = object : OsmandLocationUtils.SaveGpxListener {
|
||||||
|
|
||||||
|
override fun onSavingGpxFinish(path: String) {
|
||||||
|
log.debug("LiveTracks onSavingGpxFinish $path time ${startTime - System.currentTimeMillis()}")
|
||||||
|
val uri = AndroidUtils.getUriForFile(app, File(path))
|
||||||
|
val destinationPath = "$LIVE_TRACKS_DIR/${it.metadata.name}.gpx"
|
||||||
|
osmandAidlHelper.importGpxFromUri(uri, destinationPath, GPXUtilities.GPXColor.AQUA.name, true)
|
||||||
|
log.debug("LiveTracks importGpxFromUri finish time ${startTime - System.currentTimeMillis()}")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSavingGpxError(error: Exception) {
|
||||||
|
log.error(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OsmandLocationUtils.saveGpx(app, it, listener)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isGpxAlreadyImported(importedGpxFiles: List<AGpxFile>?, gpxFile: GPXUtilities.GPXFile): Boolean {
|
||||||
|
if (importedGpxFiles != null && importedGpxFiles.isNotEmpty()) {
|
||||||
|
val name = "${gpxFile.metadata.name}.gpx"
|
||||||
|
val aGpxFile = importedGpxFiles.firstOrNull { it.fileName == name }
|
||||||
|
|
||||||
|
if (aGpxFile != null) {
|
||||||
|
val startTimeImported = aGpxFile.details?.startTime
|
||||||
|
val endTimeImported = aGpxFile.details?.endTime
|
||||||
|
if (startTimeImported != null && endTimeImported != null) {
|
||||||
|
val startTime = gpxFile.findPointToShow()?.time
|
||||||
|
val endTime = gpxFile.lastPoint?.time
|
||||||
|
if (aGpxFile.details?.startTime == startTime && endTimeImported == endTime) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getLiveGpxFiles(): List<GPXUtilities.GPXFile> {
|
||||||
|
val currentTime = System.currentTimeMillis()
|
||||||
|
val start = currentTime - app.settings.locHistoryTime * 1000
|
||||||
|
val locationMessages = mutableListOf<LocationMessages.LocationMessage>()
|
||||||
|
|
||||||
|
app.settings.getLiveTracksInfo().forEach {
|
||||||
|
val messages = app.locationMessages.getMessagesForUserInChat(it.userId, it.chatId, it.deviceName, start, currentTime)
|
||||||
|
if (messages.isNotEmpty()) {
|
||||||
|
locationMessages.addAll(messages)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return OsmandLocationUtils.convertLocationMessagesToGpxFiles(app, locationMessages)
|
||||||
|
}
|
||||||
|
|
||||||
fun startShowingLocation() {
|
fun startShowingLocation() {
|
||||||
if (!showingLocation && !forcedStop) {
|
if (!showingLocation && !forcedStop) {
|
||||||
showingLocation = if (isUseOsmandCallback() && !app.settings.monitoringEnabled) {
|
showingLocation = if (isUseOsmandCallback() && !app.settings.monitoringEnabled) {
|
||||||
|
@ -317,6 +391,10 @@ class ShowLocationHelper(private val app: TelegramApplication) {
|
||||||
UpdateMessagesTask(app).executeOnExecutor(executor)
|
UpdateMessagesTask(app).executeOnExecutor(executor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun startUpdateTracksTask() {
|
||||||
|
UpdateTracksTask(app).executeOnExecutor(liveTracksExecutor)
|
||||||
|
}
|
||||||
|
|
||||||
private class ShowMessagesTask(private val app: TelegramApplication) : AsyncTask<TdApi.Message, Void, Void?>() {
|
private class ShowMessagesTask(private val app: TelegramApplication) : AsyncTask<TdApi.Message, Void, Void?>() {
|
||||||
|
|
||||||
override fun doInBackground(vararg messages: TdApi.Message): Void? {
|
override fun doInBackground(vararg messages: TdApi.Message): Void? {
|
||||||
|
@ -345,6 +423,14 @@ class ShowLocationHelper(private val app: TelegramApplication) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class UpdateTracksTask(private val app: TelegramApplication) : AsyncTask<Void, Void, Void?>() {
|
||||||
|
|
||||||
|
override fun doInBackground(vararg params: Void?): Void? {
|
||||||
|
app.showLocationHelper.updateTracksOnMap()
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun generatePointDetails(bearing: Float?, altitude: Float?, precision: Float?): List<String> {
|
private fun generatePointDetails(bearing: Float?, altitude: Float?, precision: Float?): List<String> {
|
||||||
val details = mutableListOf<String>()
|
val details = mutableListOf<String>()
|
||||||
if (bearing != null && bearing != 0.0f) {
|
if (bearing != null && bearing != 0.0f) {
|
||||||
|
|
|
@ -23,6 +23,7 @@ import android.widget.ImageView
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
import net.osmand.GPXUtilities
|
||||||
import net.osmand.PlatformUtil
|
import net.osmand.PlatformUtil
|
||||||
import net.osmand.aidl.gpx.AGpxBitmap
|
import net.osmand.aidl.gpx.AGpxBitmap
|
||||||
import net.osmand.telegram.R
|
import net.osmand.telegram.R
|
||||||
|
@ -30,7 +31,9 @@ import net.osmand.telegram.TelegramSettings
|
||||||
import net.osmand.telegram.helpers.LocationMessages
|
import net.osmand.telegram.helpers.LocationMessages
|
||||||
import net.osmand.telegram.helpers.OsmandAidlHelper
|
import net.osmand.telegram.helpers.OsmandAidlHelper
|
||||||
import net.osmand.telegram.helpers.TelegramUiHelper
|
import net.osmand.telegram.helpers.TelegramUiHelper
|
||||||
import net.osmand.telegram.utils.*
|
import net.osmand.telegram.utils.AndroidUtils
|
||||||
|
import net.osmand.telegram.utils.OsmandFormatter
|
||||||
|
import net.osmand.telegram.utils.OsmandLocationUtils
|
||||||
import net.osmand.util.Algorithms
|
import net.osmand.util.Algorithms
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
|
@ -42,7 +45,7 @@ class UserGpxInfoFragment : BaseDialogFragment() {
|
||||||
|
|
||||||
private val uiUtils get() = app.uiUtils
|
private val uiUtils get() = app.uiUtils
|
||||||
|
|
||||||
private var gpxFile = GPXUtilities.GPXFile()
|
private var gpxFile = GPXUtilities.GPXFile("")
|
||||||
|
|
||||||
private lateinit var mainView: View
|
private lateinit var mainView: View
|
||||||
private lateinit var dateStartBtn: TextView
|
private lateinit var dateStartBtn: TextView
|
||||||
|
@ -101,8 +104,8 @@ class UserGpxInfoFragment : BaseDialogFragment() {
|
||||||
openGpx(path)
|
openGpx(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSavingGpxError(warnings: List<String>?) {
|
override fun onSavingGpxError(error: Exception) {
|
||||||
Toast.makeText(app, warnings?.firstOrNull(), Toast.LENGTH_LONG).show()
|
Toast.makeText(app, error.message, Toast.LENGTH_LONG).show()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -198,8 +201,8 @@ class UserGpxInfoFragment : BaseDialogFragment() {
|
||||||
(activity as MainActivity).shareGpx(path)
|
(activity as MainActivity).shareGpx(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSavingGpxError(warnings: List<String>?) {
|
override fun onSavingGpxError(error: Exception) {
|
||||||
Toast.makeText(app, warnings?.firstOrNull(), Toast.LENGTH_LONG).show()
|
Toast.makeText(app, error.message, Toast.LENGTH_LONG).show()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -224,6 +227,13 @@ class UserGpxInfoFragment : BaseDialogFragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
if (liveTrackEnabled()) {
|
||||||
|
startHandler()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun startHandler() {
|
private fun startHandler() {
|
||||||
log.debug("startHandler")
|
log.debug("startHandler")
|
||||||
if (!handler.hasMessages(TRACK_UPDATE_MSG_ID)) {
|
if (!handler.hasMessages(TRACK_UPDATE_MSG_ID)) {
|
||||||
|
@ -256,10 +266,7 @@ class UserGpxInfoFragment : BaseDialogFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun saveCurrentGpxToFile(listener: OsmandLocationUtils.SaveGpxListener) {
|
private fun saveCurrentGpxToFile(listener: OsmandLocationUtils.SaveGpxListener) {
|
||||||
if (!gpxFile.isEmpty) {
|
OsmandLocationUtils.saveGpx(app, gpxFile, listener)
|
||||||
val file = File(app.getExternalFilesDir(null), TRACKS_DIR)
|
|
||||||
OsmandLocationUtils.saveGpx(app, listener, file, gpxFile)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun readFromBundle(bundle: Bundle?) {
|
private fun readFromBundle(bundle: Bundle?) {
|
||||||
|
@ -320,7 +327,7 @@ class UserGpxInfoFragment : BaseDialogFragment() {
|
||||||
checkTime()
|
checkTime()
|
||||||
locationMessages = app.locationMessages.getMessagesForUserInChat(userId, chatId, deviceName, startCalendar.timeInMillis, endCalendar.timeInMillis)
|
locationMessages = app.locationMessages.getMessagesForUserInChat(userId, chatId, deviceName, startCalendar.timeInMillis, endCalendar.timeInMillis)
|
||||||
|
|
||||||
gpxFile = OsmandLocationUtils.convertLocationMessagesToGpxFiles(locationMessages).firstOrNull()?:GPXUtilities.GPXFile()
|
gpxFile = OsmandLocationUtils.convertLocationMessagesToGpxFiles(app, locationMessages).firstOrNull() ?: GPXUtilities.GPXFile(app.packageName)
|
||||||
updateGPXStatisticRow()
|
updateGPXStatisticRow()
|
||||||
updateDateAndTimeButtons()
|
updateDateAndTimeButtons()
|
||||||
updateGPXMap()
|
updateGPXMap()
|
||||||
|
@ -390,8 +397,8 @@ class UserGpxInfoFragment : BaseDialogFragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSavingGpxError(warnings: List<String>?) {
|
override fun onSavingGpxError(error: Exception) {
|
||||||
log.debug("onSavingGpxError ${warnings?.firstOrNull()}")
|
log.error(error)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,24 +0,0 @@
|
||||||
package net.osmand.telegram.utils;
|
|
||||||
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
public interface LocationPoint {
|
|
||||||
|
|
||||||
public double getLatitude();
|
|
||||||
|
|
||||||
public double getLongitude();
|
|
||||||
|
|
||||||
public int getColor();
|
|
||||||
|
|
||||||
public boolean isVisible();
|
|
||||||
|
|
||||||
// public PointDescription getPointDescription(Context ctx);
|
|
||||||
|
|
||||||
// public String getSpeakableName();
|
|
||||||
|
|
||||||
//public void prepareCommandPlayer(CommandBuilder cmd, String names);
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,6 +1,7 @@
|
||||||
package net.osmand.telegram.utils
|
package net.osmand.telegram.utils
|
||||||
|
|
||||||
import android.os.AsyncTask
|
import android.os.AsyncTask
|
||||||
|
import net.osmand.GPXUtilities
|
||||||
import net.osmand.Location
|
import net.osmand.Location
|
||||||
import net.osmand.data.LatLon
|
import net.osmand.data.LatLon
|
||||||
import net.osmand.telegram.TelegramApplication
|
import net.osmand.telegram.TelegramApplication
|
||||||
|
@ -15,6 +16,7 @@ import org.drinkless.td.libcore.telegram.TdApi
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import kotlin.math.abs
|
||||||
|
|
||||||
const val TRACKS_DIR = "tracker/"
|
const val TRACKS_DIR = "tracker/"
|
||||||
|
|
||||||
|
@ -412,7 +414,7 @@ object OsmandLocationUtils {
|
||||||
return TdApi.InputMessageText(TdApi.FormattedText(textMessage, entities.toTypedArray()), true, true)
|
return TdApi.InputMessageText(TdApi.FormattedText(textMessage, entities.toTypedArray()), true, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun convertLocationMessagesToGpxFiles(items: List<LocationMessage>, newGpxPerChat: Boolean = true): List<GPXUtilities.GPXFile> {
|
fun convertLocationMessagesToGpxFiles(app: TelegramApplication, items: List<LocationMessage>, newGpxPerChat: Boolean = true): List<GPXUtilities.GPXFile> {
|
||||||
val dataTracks = ArrayList<GPXUtilities.GPXFile>()
|
val dataTracks = ArrayList<GPXUtilities.GPXFile>()
|
||||||
|
|
||||||
var previousTime: Long = -1
|
var previousTime: Long = -1
|
||||||
|
@ -432,24 +434,24 @@ object OsmandLocationUtils {
|
||||||
}
|
}
|
||||||
countedLocations++
|
countedLocations++
|
||||||
if (previousUserId != userId || (newGpxPerChat && previousChatId != chatId)) {
|
if (previousUserId != userId || (newGpxPerChat && previousChatId != chatId)) {
|
||||||
gpx = GPXUtilities.GPXFile()
|
gpx = GPXUtilities.GPXFile(app.packageName).apply {
|
||||||
gpx!!.chatId = chatId
|
metadata = GPXUtilities.Metadata().apply {
|
||||||
gpx!!.userId = userId
|
name = getGpxFileNameForUserId(app, userId, time)
|
||||||
|
}
|
||||||
|
}
|
||||||
previousTime = 0
|
previousTime = 0
|
||||||
track = null
|
track = null
|
||||||
segment = null
|
segment = null
|
||||||
dataTracks.add(gpx!!)
|
dataTracks.add(gpx!!)
|
||||||
}
|
}
|
||||||
val pt = GPXUtilities.WptPt()
|
val pt = GPXUtilities.WptPt()
|
||||||
pt.userId = userId
|
|
||||||
pt.chatId = chatId
|
|
||||||
pt.lat = it.lat
|
pt.lat = it.lat
|
||||||
pt.lon = it.lon
|
pt.lon = it.lon
|
||||||
pt.ele = it.altitude
|
pt.ele = it.altitude
|
||||||
pt.speed = it.speed
|
pt.speed = it.speed
|
||||||
pt.hdop = it.hdop
|
pt.hdop = it.hdop
|
||||||
pt.time = time
|
pt.time = time
|
||||||
val currentInterval = Math.abs(time - previousTime)
|
val currentInterval = abs(time - previousTime)
|
||||||
if (track != null) {
|
if (track != null) {
|
||||||
if (currentInterval < 30 * 60 * 1000) {
|
if (currentInterval < 30 * 60 * 1000) {
|
||||||
// 30 minute - same segment
|
// 30 minute - same segment
|
||||||
|
@ -475,13 +477,27 @@ object OsmandLocationUtils {
|
||||||
return dataTracks
|
return dataTracks
|
||||||
}
|
}
|
||||||
|
|
||||||
fun saveGpx(app: TelegramApplication, listener: SaveGpxListener, dir: File, gpxFile: GPXUtilities.GPXFile) {
|
fun saveGpx(app: TelegramApplication, gpxFile: GPXUtilities.GPXFile, listener: SaveGpxListener) {
|
||||||
if (!gpxFile.isEmpty) {
|
if (!gpxFile.isEmpty) {
|
||||||
val task = SaveGPXTrackToFileTask(app, listener, gpxFile, dir, 0)
|
val dir = File(app.getExternalFilesDir(null), TRACKS_DIR)
|
||||||
|
val task = SaveGPXTrackToFileTask(listener, gpxFile, dir)
|
||||||
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR)
|
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getGpxFileNameForUserId(app: TelegramApplication, userId: Int, time: Long): String {
|
||||||
|
var userName = userId.toString()
|
||||||
|
try {
|
||||||
|
val user = app.telegramHelper.getUser(userId)
|
||||||
|
if (user != null) {
|
||||||
|
userName = TelegramUiHelper.getUserName(user)
|
||||||
|
}
|
||||||
|
} catch (e: NumberFormatException) {
|
||||||
|
//ignore
|
||||||
|
}
|
||||||
|
return "${userName}_${UTC_DATE_FORMAT.format(Date(time))}"
|
||||||
|
}
|
||||||
|
|
||||||
abstract class MessageLocation : TdApi.MessageContent() {
|
abstract class MessageLocation : TdApi.MessageContent() {
|
||||||
|
|
||||||
var lat: Double = Double.NaN
|
var lat: Double = Double.NaN
|
||||||
|
@ -521,47 +537,34 @@ object OsmandLocationUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SaveGPXTrackToFileTask internal constructor(
|
private class SaveGPXTrackToFileTask internal constructor(
|
||||||
private val app: TelegramApplication, private val listener: SaveGpxListener?,
|
private val listener: SaveGpxListener?,
|
||||||
private val gpxFile: GPXUtilities.GPXFile, private val dir: File, private val userId: Int
|
private val gpxFile: GPXUtilities.GPXFile,
|
||||||
|
private val dir: File
|
||||||
) :
|
) :
|
||||||
AsyncTask<Void, Void, List<String>>() {
|
AsyncTask<Void, Void, java.lang.Exception>() {
|
||||||
|
|
||||||
override fun doInBackground(vararg params: Void): List<String> {
|
override fun doInBackground(vararg params: Void): Exception? {
|
||||||
val warnings = ArrayList<String>()
|
|
||||||
dir.mkdirs()
|
dir.mkdirs()
|
||||||
if (dir.parentFile.canWrite()) {
|
if (dir.parentFile.canWrite()) {
|
||||||
if (dir.exists()) {
|
if (dir.exists()) {
|
||||||
// save file
|
// save file
|
||||||
var fout = File(dir, "$userId.gpx")
|
|
||||||
if (!gpxFile.isEmpty) {
|
if (!gpxFile.isEmpty) {
|
||||||
val pt = gpxFile.findPointToShow()
|
val fileName = gpxFile.metadata.name
|
||||||
|
val fout = File(dir, "$fileName.gpx")
|
||||||
|
|
||||||
val user = app.telegramHelper.getUser(pt!!.userId)
|
return GPXUtilities.writeGpxFile(fout, gpxFile)
|
||||||
val fileName: String
|
|
||||||
fileName = if (user != null) {
|
|
||||||
(TelegramUiHelper.getUserName(user) + "_" + SimpleDateFormat("yyyy-MM-dd", Locale.US).format(Date(pt.time)))
|
|
||||||
} else {
|
|
||||||
userId.toString() + "_" + SimpleDateFormat("yyyy-MM-dd", Locale.US).format(Date(pt.time))
|
|
||||||
}
|
|
||||||
fout = File(dir, "$fileName.gpx")
|
|
||||||
}
|
|
||||||
val warn = GPXUtilities.writeGpxFile(fout, gpxFile, app)
|
|
||||||
if (warn != null) {
|
|
||||||
warnings.add(warn)
|
|
||||||
return warnings
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
return warnings
|
override fun onPostExecute(warning: Exception?) {
|
||||||
}
|
|
||||||
|
|
||||||
override fun onPostExecute(warnings: List<String>?) {
|
|
||||||
if (listener != null) {
|
if (listener != null) {
|
||||||
if (warnings != null && warnings.isEmpty()) {
|
if (warning == null) {
|
||||||
listener.onSavingGpxFinish(gpxFile.path)
|
listener.onSavingGpxFinish(gpxFile.path)
|
||||||
} else {
|
} else {
|
||||||
listener.onSavingGpxError(warnings)
|
listener.onSavingGpxError(warning)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -571,6 +574,6 @@ object OsmandLocationUtils {
|
||||||
|
|
||||||
fun onSavingGpxFinish(path: String)
|
fun onSavingGpxFinish(path: String)
|
||||||
|
|
||||||
fun onSavingGpxError(warnings: List<String>?)
|
fun onSavingGpxError(error: Exception)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -74,7 +74,6 @@ import net.osmand.plus.audionotes.AudioVideoNotesPlugin;
|
||||||
import net.osmand.plus.dialogs.ConfigureMapMenu;
|
import net.osmand.plus.dialogs.ConfigureMapMenu;
|
||||||
import net.osmand.plus.helpers.ColorDialogs;
|
import net.osmand.plus.helpers.ColorDialogs;
|
||||||
import net.osmand.plus.helpers.ExternalApiHelper;
|
import net.osmand.plus.helpers.ExternalApiHelper;
|
||||||
import net.osmand.plus.helpers.LockHelper;
|
|
||||||
import net.osmand.plus.mapcontextmenu.MapContextMenu;
|
import net.osmand.plus.mapcontextmenu.MapContextMenu;
|
||||||
import net.osmand.plus.mapcontextmenu.other.IContextMenuButtonListener;
|
import net.osmand.plus.mapcontextmenu.other.IContextMenuButtonListener;
|
||||||
import net.osmand.plus.monitoring.OsmandMonitoringPlugin;
|
import net.osmand.plus.monitoring.OsmandMonitoringPlugin;
|
||||||
|
@ -1315,6 +1314,9 @@ public class OsmandAidlApi {
|
||||||
File destination = app.getAppPath(IndexConstants.GPX_INDEX_DIR + destinationPath);
|
File destination = app.getAppPath(IndexConstants.GPX_INDEX_DIR + destinationPath);
|
||||||
if (destination.getParentFile().canWrite()) {
|
if (destination.getParentFile().canWrite()) {
|
||||||
boolean destinationExists = destination.exists();
|
boolean destinationExists = destination.exists();
|
||||||
|
if (!destinationExists) {
|
||||||
|
Algorithms.createParentDirsForFile(destination);
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
Algorithms.fileCopy(source, destination);
|
Algorithms.fileCopy(source, destination);
|
||||||
finishGpxImport(destinationExists, destination, color, show);
|
finishGpxImport(destinationExists, destination, color, show);
|
||||||
|
@ -1336,6 +1338,9 @@ public class OsmandAidlApi {
|
||||||
gpxParcelDescriptor = app.getContentResolver().openFileDescriptor(gpxUri, "r");
|
gpxParcelDescriptor = app.getContentResolver().openFileDescriptor(gpxUri, "r");
|
||||||
if (gpxParcelDescriptor != null) {
|
if (gpxParcelDescriptor != null) {
|
||||||
boolean destinationExists = destination.exists();
|
boolean destinationExists = destination.exists();
|
||||||
|
if (!destinationExists) {
|
||||||
|
Algorithms.createParentDirsForFile(destination);
|
||||||
|
}
|
||||||
FileDescriptor fileDescriptor = gpxParcelDescriptor.getFileDescriptor();
|
FileDescriptor fileDescriptor = gpxParcelDescriptor.getFileDescriptor();
|
||||||
InputStream is = new FileInputStream(fileDescriptor);
|
InputStream is = new FileInputStream(fileDescriptor);
|
||||||
FileOutputStream fout = new FileOutputStream(destination);
|
FileOutputStream fout = new FileOutputStream(destination);
|
||||||
|
@ -1370,6 +1375,9 @@ public class OsmandAidlApi {
|
||||||
InputStream is = new ByteArrayInputStream(sourceRawData.getBytes());
|
InputStream is = new ByteArrayInputStream(sourceRawData.getBytes());
|
||||||
FileOutputStream fout = new FileOutputStream(destination);
|
FileOutputStream fout = new FileOutputStream(destination);
|
||||||
boolean destinationExists = destination.exists();
|
boolean destinationExists = destination.exists();
|
||||||
|
if (!destinationExists) {
|
||||||
|
Algorithms.createParentDirsForFile(destination);
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
Algorithms.streamCopy(is, fout);
|
Algorithms.streamCopy(is, fout);
|
||||||
finishGpxImport(destinationExists, destination, color, show);
|
finishGpxImport(destinationExists, destination, color, show);
|
||||||
|
|
Loading…
Reference in a new issue