diff --git a/OsmAnd-shared/src/androidMain/kotlin/net/osmand/shared/extensions/FileExtensions.kt b/OsmAnd-shared/src/androidMain/kotlin/net/osmand/shared/extensions/FileExtensions.kt index 76bf63e27e9..4658373d503 100644 --- a/OsmAnd-shared/src/androidMain/kotlin/net/osmand/shared/extensions/FileExtensions.kt +++ b/OsmAnd-shared/src/androidMain/kotlin/net/osmand/shared/extensions/FileExtensions.kt @@ -3,5 +3,5 @@ package net.osmand.shared.extensions import net.osmand.shared.io.KFile import java.io.File -fun File.kFile(): KFile = KFile(this.absolutePath) -fun KFile.jFile(): File = File(this.absolutePath()) +fun File.kFile(): KFile = KFile(this.path) +fun KFile.jFile(): File = File(if (this.isPathEmpty()) "" else this.path()) diff --git a/OsmAnd-shared/src/commonMain/kotlin/net/osmand/shared/gpx/GpxDatabase.kt b/OsmAnd-shared/src/commonMain/kotlin/net/osmand/shared/gpx/GpxDatabase.kt index c72bf5e4e5a..da246054c42 100644 --- a/OsmAnd-shared/src/commonMain/kotlin/net/osmand/shared/gpx/GpxDatabase.kt +++ b/OsmAnd-shared/src/commonMain/kotlin/net/osmand/shared/gpx/GpxDatabase.kt @@ -30,8 +30,8 @@ class GpxDatabase { const val TMP_NAME_COLUMN_COUNT = "itemsCount" const val UNKNOWN_TIME_THRESHOLD = 10L val GPX_UPDATE_PARAMETERS_START = "UPDATE $GPX_TABLE_NAME SET " - val GPX_FIND_BY_NAME_AND_DIR = - " WHERE ${FILE_NAME.columnName} = ? AND ${FILE_DIR.columnName} = ?" + val GPX_FIND_BY_NAME_AND_DIR = " WHERE ${FILE_NAME.columnName} = ? AND ${FILE_DIR.columnName} = ?" + val GPX_NAME_AND_DIR = "${FILE_NAME.columnName} = ? AND ${FILE_DIR.columnName} = ?" val GPX_MIN_CREATE_DATE = "SELECT MIN(${FILE_CREATION_TIME.columnName}) FROM $GPX_TABLE_NAME WHERE ${FILE_CREATION_TIME.columnName} > $UNKNOWN_TIME_THRESHOLD" val GPX_MAX_COLUMN_VALUE = "SELECT MAX(%s) FROM $GPX_TABLE_NAME" @@ -140,6 +140,31 @@ class GpxDatabase { } } + fun remove(files: Collection): Boolean { + if (files.isEmpty()) return false + + val time = currentTimeMillis() + var db: SQLiteConnection? = null + try { + db = openConnection(false) + db?.let { + val fileDeletionMap = files.groupBy { GpxDbUtils.getTableName(it) } + fileDeletionMap.forEach { (tableName, files) -> + files.chunked(BATCH_SIZE).forEach { batch -> + val deleteConditions = batch.joinToString(separator = " OR ") { "($GPX_NAME_AND_DIR)" } + val args: Array = batch.flatMap { listOf(it.name(), GpxDbUtils.getGpxFileDir(it)) }.toTypedArray() + db.execSQL("DELETE FROM $tableName WHERE $deleteConditions", args) + } + } + log.info("Remove gpx files from db count=${files.size} in ${currentTimeMillis() - time} ms") + return true + } + return false + } finally { + db?.close() + } + } + fun add(item: DataItem): Boolean { var db: SQLiteConnection? = null try { diff --git a/OsmAnd-shared/src/commonMain/kotlin/net/osmand/shared/gpx/GpxDbHelper.kt b/OsmAnd-shared/src/commonMain/kotlin/net/osmand/shared/gpx/GpxDbHelper.kt index 6dbc71dab86..ca7bfa10e7c 100644 --- a/OsmAnd-shared/src/commonMain/kotlin/net/osmand/shared/gpx/GpxDbHelper.kt +++ b/OsmAnd-shared/src/commonMain/kotlin/net/osmand/shared/gpx/GpxDbHelper.kt @@ -1,7 +1,7 @@ package net.osmand.shared.gpx -import co.touchlab.stately.collections.ConcurrentMutableList import co.touchlab.stately.collections.ConcurrentMutableMap +import co.touchlab.stately.concurrency.AtomicInt import co.touchlab.stately.concurrency.Synchronizable import co.touchlab.stately.concurrency.synchronize import kotlinx.coroutines.Dispatchers @@ -13,21 +13,21 @@ import kotlinx.coroutines.runBlocking import net.osmand.shared.api.SQLiteAPI.SQLiteConnection import net.osmand.shared.data.StringIntPair import net.osmand.shared.extensions.currentTimeMillis -import net.osmand.shared.gpx.GpxReader.GpxDbReaderCallback +import net.osmand.shared.gpx.GpxReader.GpxReaderAdapter import net.osmand.shared.io.KFile import net.osmand.shared.util.LoggerFactory -object GpxDbHelper : GpxDbReaderCallback { +object GpxDbHelper : GpxReaderAdapter { val log = LoggerFactory.getLogger("GpxDbHelper") private val database: GpxDatabase by lazy { GpxDatabase() } private val dirItems = ConcurrentMutableMap() private val dataItems = ConcurrentMutableMap() + private var itemsVersion = AtomicInt(0) - private val readingItems = ConcurrentMutableList() - private val readingItemsMap = ConcurrentMutableMap() + private val readingItemsMap = mutableMapOf() private val readingItemsCallbacks = mutableMapOf?>() private const val READER_TASKS_LIMIT = 4 @@ -55,7 +55,7 @@ object GpxDbHelper : GpxDbReaderCallback { private suspend fun loadGpxItems() { val start = currentTimeMillis() - val items = getItems() + val items = readItems() val startEx = currentTimeMillis() val fileExistenceMap = getFileExistenceMap(items) log.info("Time to getFileExistenceMap ${currentTimeMillis() - startEx} ms, ${items.size} items") @@ -70,8 +70,9 @@ object GpxDbHelper : GpxDbReaderCallback { itemsToRemove.add(file) } } - putToCacheBulk(itemsToCache); - removeFromCacheBulk(itemsToRemove); + putToCacheBulk(itemsToCache) + removeFromCacheBulk(itemsToRemove) + database.remove(itemsToRemove) log.info("Time to loadGpxItems ${currentTimeMillis() - start} ms, ${items.size} items") } @@ -86,7 +87,7 @@ object GpxDbHelper : GpxDbReaderCallback { private fun loadGpxDirItems() { val start = currentTimeMillis() - val items = getDirItems() + val items = readDirItems() items.forEach { item -> val file = item.file if (file.exists()) { @@ -100,12 +101,15 @@ object GpxDbHelper : GpxDbReaderCallback { fun isInitialized() = initialized + fun getItemsVersion() = itemsVersion.get() + private fun putToCache(item: DataItem) { val file = item.file when (item) { is GpxDataItem -> dataItems[file] = item is GpxDirItem -> dirItems[file] = item } + itemsVersion.incrementAndGet() } private fun removeFromCache(file: KFile) { @@ -114,14 +118,17 @@ object GpxDbHelper : GpxDbReaderCallback { } else { dirItems.remove(file) } + itemsVersion.incrementAndGet() } private fun putToCacheBulk(itemsToCache: Map) { dataItems.putAll(itemsToCache) + itemsVersion.incrementAndGet() } private fun removeFromCacheBulk(filesToRemove: Set) { dataItems.keys.removeAll(filesToRemove) + itemsVersion.incrementAndGet() } fun rename(currentFile: KFile, newFile: KFile): Boolean { @@ -167,6 +174,12 @@ object GpxDbHelper : GpxDbReaderCallback { return res } + fun remove(files: Collection): Boolean { + val res = database.remove(files) + removeFromCacheBulk(files.toSet()) + return res + } + fun remove(item: DataItem): Boolean { val file = item.file val res = database.remove(file) @@ -187,10 +200,13 @@ object GpxDbHelper : GpxDbReaderCallback { return res } - fun getItemsBlocking(): List = database.getGpxDataItemsBlocking() - suspend fun getItems(): List = database.getGpxDataItems() + fun getItems() = dataItems.values.toList() + + fun getDirItems() = dirItems.values.toList() - fun getDirItems(): List = database.getGpxDirItems() + private suspend fun readItems(): List = database.getGpxDataItems() + + private fun readDirItems(): List = database.getGpxDirItems() fun getStringIntItemsCollection( columnName: String, @@ -229,7 +245,7 @@ object GpxDbHelper : GpxDbReaderCallback { } fun getItem(file: KFile, callback: GpxDataItemCallback?): GpxDataItem? { - if (file.path().isEmpty()) { + if (file.isPathEmpty()) { return null } val item = dataItems[file] @@ -250,7 +266,7 @@ object GpxDbHelper : GpxDbReaderCallback { fun getSplitItemsBlocking(): List = runBlocking { getSplitItems() } suspend fun getSplitItems(): List { - return getItems().filter { + return readItems().filter { it.getAppearanceParameter(GpxParameter.SPLIT_TYPE) != 0 } } @@ -274,7 +290,7 @@ object GpxDbHelper : GpxDbReaderCallback { fun isReading(): Boolean = readerSync.synchronize { readers.isNotEmpty() } private fun isReading(file: KFile): Boolean = - readerSync.synchronize { readingItems.contains(file) || readers.any { it.file == file } } + readerSync.synchronize { readingItemsMap.contains(file) || readers.any { it.isReading(file) } } private fun readGpxItem(file: KFile, item: GpxDataItem?, callback: GpxDataItemCallback?) { readerSync.synchronize { @@ -283,7 +299,6 @@ object GpxDbHelper : GpxDbReaderCallback { } if (!isReading(file)) { readingItemsMap[file] = item ?: GpxDataItem(file) - readingItems.add(file) if (readers.size < READER_TASKS_LIMIT) { startReading() } @@ -293,8 +308,7 @@ object GpxDbHelper : GpxDbReaderCallback { private fun startReading() { readerSync.synchronize { - readers.add(GpxReader(readingItems, readingItemsMap, this).apply { execute() }) - log.info(">>>> GpxReader created = ${readers.size}") + readers.add(GpxReader(this).apply { execute() }) } } @@ -302,12 +316,18 @@ object GpxDbHelper : GpxDbReaderCallback { readerSync.synchronize { readers.forEach { it.cancel() } readers.clear() - log.info(">>>> GpxReaders stopped") } } fun getGPXDatabase(): GpxDatabase = database + override fun pullNextFileItem(action: ((Pair?) -> Unit)?): Pair? = + readerSync.synchronize { + val result = readingItemsMap.entries.firstOrNull()?.toPair()?.apply { readingItemsMap.remove(first) } + action?.invoke(result) + result + } + override fun onGpxDataItemRead(item: GpxDataItem) { putGpxDataItemToSmartFolder(item) } @@ -336,7 +356,6 @@ object GpxDbHelper : GpxDbReaderCallback { override fun onReadingCancelled() { readerSync.synchronize { - readingItems.clear() readingItemsMap.clear() readingItemsCallbacks.clear() } @@ -344,12 +363,10 @@ object GpxDbHelper : GpxDbReaderCallback { override fun onReadingFinished(reader: GpxReader, cancelled: Boolean) { readerSync.synchronize { - if (readingItems.isNotEmpty() && readers.size < READER_TASKS_LIMIT && !cancelled) { + if (readingItemsMap.isNotEmpty() && readers.size < READER_TASKS_LIMIT && !cancelled) { startReading() - } else { - readers.remove(reader) } - log.info(">>>> GpxReader onReadingFinished readers=${readers.size}") + readers.remove(reader) } } } \ No newline at end of file diff --git a/OsmAnd-shared/src/commonMain/kotlin/net/osmand/shared/gpx/GpxReader.kt b/OsmAnd-shared/src/commonMain/kotlin/net/osmand/shared/gpx/GpxReader.kt index ddc8b5fc478..4f79184b486 100644 --- a/OsmAnd-shared/src/commonMain/kotlin/net/osmand/shared/gpx/GpxReader.kt +++ b/OsmAnd-shared/src/commonMain/kotlin/net/osmand/shared/gpx/GpxReader.kt @@ -8,11 +8,8 @@ import net.osmand.shared.io.KFile import net.osmand.shared.util.LoggerFactory import net.osmand.shared.util.PlatformUtil -class GpxReader( - private val readingItems: MutableList, - private val readingItemsMap: MutableMap, - private val listener: GpxDbReaderCallback? -) : KAsyncTask(true) { +class GpxReader(private val adapter: GpxReaderAdapter) + : KAsyncTask(true) { companion object { private val log = LoggerFactory.getLogger("GpxReader") @@ -23,7 +20,8 @@ class GpxReader( } private val database: GpxDatabase = GpxDbHelper.getGPXDatabase() - var file: KFile? = null + private var currentFile: KFile? = null + private var currentItem: GpxDataItem? = null override suspend fun doInBackground(vararg params: Unit) { waitForInitialization() @@ -37,45 +35,56 @@ class GpxReader( } private fun doReading() { - log.info(">>>> start GpxReader ===== ") var filesCount = 0 val conn = database.openConnection(false) if (conn != null) { try { - file = readingItems.removeFirstOrNull() + var file: KFile? + var item: GpxDataItem? + pullNextFileItem() + file = currentFile + item = currentItem while (file != null && !isCancelled()) { - var item = readingItemsMap.remove(file) if (GpxDbUtils.isAnalyseNeeded(item)) { - item = updateGpxDataItem(conn, item, file!!) + item = updateGpxDataItem(conn, item, file) } if (item != null) { - listener?.onGpxDataItemRead(item) + adapter.onGpxDataItemRead(item) publishProgress(item) } - file = readingItems.removeFirstOrNull() + + pullNextFileItem() + file = currentFile + item = currentItem filesCount++ } } catch (e: Exception) { log.error(e.message) } finally { conn.close() - log.info(">>>> done GpxReader ===== filesCount=$filesCount") } } else { cancel() } } + private fun pullNextFileItem() { + adapter.pullNextFileItem { + currentFile = it?.first + currentItem = it?.second + } + } + override fun onProgressUpdate(vararg values: GpxDataItem) { - listener?.onProgressUpdate(*values) + adapter.onProgressUpdate(*values) } override fun onCancelled() { - listener?.onReadingCancelled() + adapter.onReadingCancelled() } override fun onPostExecute(result: Unit) { - listener?.onReadingFinished(this, isCancelled()) + adapter.onReadingFinished(this, isCancelled()) } private fun updateGpxDataItem(conn: SQLiteConnection, item: GpxDataItem?, file: KFile): GpxDataItem { @@ -134,12 +143,16 @@ class GpxReader( } } - fun isReading(): Boolean = readingItems.isNotEmpty() || file != null + fun isReading(): Boolean = isRunning() + + fun isReading(file: KFile): Boolean = currentFile == file + + interface GpxReaderAdapter { + fun pullNextFileItem(action: ((Pair?) -> Unit)? = null): Pair? - interface GpxDbReaderCallback { - fun onGpxDataItemRead(item: GpxDataItem) - fun onProgressUpdate(vararg dataItems: GpxDataItem) - fun onReadingCancelled() - fun onReadingFinished(reader: GpxReader, cancelled: Boolean) + fun onGpxDataItemRead(item: GpxDataItem) {} + fun onProgressUpdate(vararg dataItems: GpxDataItem) {} + fun onReadingCancelled() {} + fun onReadingFinished(reader: GpxReader, cancelled: Boolean) {} } } \ No newline at end of file diff --git a/OsmAnd-shared/src/commonMain/kotlin/net/osmand/shared/gpx/TrackFolderLoaderTask.kt b/OsmAnd-shared/src/commonMain/kotlin/net/osmand/shared/gpx/TrackFolderLoaderTask.kt index 2d58156f439..5b1db67aa09 100644 --- a/OsmAnd-shared/src/commonMain/kotlin/net/osmand/shared/gpx/TrackFolderLoaderTask.kt +++ b/OsmAnd-shared/src/commonMain/kotlin/net/osmand/shared/gpx/TrackFolderLoaderTask.kt @@ -27,6 +27,7 @@ class TrackFolderLoaderTask( private const val PROGRESS_BATCH_SIZE = 70 private var cachedRootFolder: TrackFolder? = null + private var cachedDbItemsVersion = -1 } private var loadingTime = 0L @@ -35,7 +36,7 @@ class TrackFolderLoaderTask( private var progressSync = Synchronizable() private fun shouldLoadFolder(cachedRootFolder: TrackFolder?) = - forceLoad || cachedRootFolder == null || !folder.isRootFolder + forceLoad || cachedRootFolder == null || !folder.isRootFolder || cachedDbItemsVersion != GpxDbHelper.getItemsVersion() override fun onPreExecute() { if (shouldLoadFolder(cachedRootFolder)) listener.loadTracksStarted() @@ -59,6 +60,7 @@ class TrackFolderLoaderTask( loadGPXFolder(folder, progress) if (folder.isRootFolder) { Companion.cachedRootFolder = TrackFolder(folder) + cachedDbItemsVersion = GpxDbHelper.getItemsVersion() } listener.tracksLoaded(folder) @@ -155,7 +157,7 @@ class TrackFolderLoaderTask( if (file == item.file) { trackItem.dataItem = item } - if (lastItem) { + if (lastItem && !isRunning()) { resetCachedData(folder) listener.deferredLoadTracksFinished(folder) } diff --git a/OsmAnd-shared/src/commonMain/kotlin/net/osmand/shared/io/KFile.kt b/OsmAnd-shared/src/commonMain/kotlin/net/osmand/shared/io/KFile.kt index c77c913764a..ada57a50c1d 100644 --- a/OsmAnd-shared/src/commonMain/kotlin/net/osmand/shared/io/KFile.kt +++ b/OsmAnd-shared/src/commonMain/kotlin/net/osmand/shared/io/KFile.kt @@ -42,6 +42,11 @@ class KFile { return if (parent != null) KFile(parent) else null } + fun isPathEmpty():Boolean { + val path = path() + return path.isEmpty() || path == "." || path == Path.DIRECTORY_SEPARATOR + } + fun exists(): Boolean = nativeFile.exists() fun isAbsolute(): Boolean = path.isAbsolute diff --git a/OsmAnd/res/drawable/ic_action_car_obd2.xml b/OsmAnd/res/drawable/ic_action_car_obd2.xml new file mode 100644 index 00000000000..2d678873fe7 --- /dev/null +++ b/OsmAnd/res/drawable/ic_action_car_obd2.xml @@ -0,0 +1,14 @@ + + + + diff --git a/OsmAnd/res/drawable/ic_action_obd2_connector_disable.xml b/OsmAnd/res/drawable/ic_action_obd2_connector_disable.xml new file mode 100644 index 00000000000..c78fe1909cb --- /dev/null +++ b/OsmAnd/res/drawable/ic_action_obd2_connector_disable.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + diff --git a/OsmAnd/res/drawable/ic_action_obd2_connector_disconnect.xml b/OsmAnd/res/drawable/ic_action_obd2_connector_disconnect.xml new file mode 100644 index 00000000000..e6c557a1e88 --- /dev/null +++ b/OsmAnd/res/drawable/ic_action_obd2_connector_disconnect.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + diff --git a/OsmAnd/res/drawable/ic_action_obd2_connector_search.xml b/OsmAnd/res/drawable/ic_action_obd2_connector_search.xml new file mode 100644 index 00000000000..6fb7932f0a9 --- /dev/null +++ b/OsmAnd/res/drawable/ic_action_obd2_connector_search.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + diff --git a/OsmAnd/res/drawable/ic_action_vehicle_metrics_colored_day.xml b/OsmAnd/res/drawable/ic_action_vehicle_metrics_colored_day.xml new file mode 100644 index 00000000000..aec7ce9c64f --- /dev/null +++ b/OsmAnd/res/drawable/ic_action_vehicle_metrics_colored_day.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/OsmAnd/res/drawable/ic_action_vehicle_metrics_colored_night.xml b/OsmAnd/res/drawable/ic_action_vehicle_metrics_colored_night.xml new file mode 100644 index 00000000000..c871f654cff --- /dev/null +++ b/OsmAnd/res/drawable/ic_action_vehicle_metrics_colored_night.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/OsmAnd/res/drawable/img_help_vehicle_metrics_day.xml b/OsmAnd/res/drawable/img_help_vehicle_metrics_day.xml new file mode 100644 index 00000000000..79898863792 --- /dev/null +++ b/OsmAnd/res/drawable/img_help_vehicle_metrics_day.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + diff --git a/OsmAnd/res/drawable/img_help_vehicle_metrics_night.xml b/OsmAnd/res/drawable/img_help_vehicle_metrics_night.xml new file mode 100644 index 00000000000..b7afb3b41cf --- /dev/null +++ b/OsmAnd/res/drawable/img_help_vehicle_metrics_night.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + diff --git a/OsmAnd/res/drawable/widget_obd_car_day.xml b/OsmAnd/res/drawable/widget_obd_car_day.xml new file mode 100644 index 00000000000..7821b0621e9 --- /dev/null +++ b/OsmAnd/res/drawable/widget_obd_car_day.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + diff --git a/OsmAnd/res/drawable/widget_obd_car_night.xml b/OsmAnd/res/drawable/widget_obd_car_night.xml new file mode 100644 index 00000000000..6f0b510adb7 --- /dev/null +++ b/OsmAnd/res/drawable/widget_obd_car_night.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + diff --git a/OsmAnd/res/drawable/widget_obd_vehicle_info_day.xml b/OsmAnd/res/drawable/widget_obd_vehicle_info_day.xml new file mode 100644 index 00000000000..9b6fb4b0c5a --- /dev/null +++ b/OsmAnd/res/drawable/widget_obd_vehicle_info_day.xml @@ -0,0 +1,27 @@ + + + + + + + + + diff --git a/OsmAnd/res/drawable/widget_obd_vehicle_info_night.xml b/OsmAnd/res/drawable/widget_obd_vehicle_info_night.xml new file mode 100644 index 00000000000..226297682f8 --- /dev/null +++ b/OsmAnd/res/drawable/widget_obd_vehicle_info_night.xml @@ -0,0 +1,27 @@ + + + + + + + + + diff --git a/OsmAnd/src/net/osmand/aidl/OsmandAidlApi.java b/OsmAnd/src/net/osmand/aidl/OsmandAidlApi.java index d1ef9f519b8..37db5d6108b 100644 --- a/OsmAnd/src/net/osmand/aidl/OsmandAidlApi.java +++ b/OsmAnd/src/net/osmand/aidl/OsmandAidlApi.java @@ -143,6 +143,7 @@ import net.osmand.shared.gpx.GpxDataItem; import net.osmand.shared.gpx.GpxFile; import net.osmand.shared.gpx.GpxTrackAnalysis; +import net.osmand.shared.io.KFile; import net.osmand.util.Algorithms; import org.apache.commons.logging.Log; @@ -1527,64 +1528,58 @@ boolean getActiveGpxV2(List files) { } boolean getImportedGpxV2(List files) { - List gpxDataItems = app.getGpxDbHelper().getItemsBlocking(); + List gpxDataItems = app.getGpxDbHelper().getItems(); for (GpxDataItem dataItem : gpxDataItems) { - File file = SharedUtil.jFile(dataItem.getFile()); - if (file.exists()) { - String fileName = file.getName(); - String absolutePath = file.getAbsolutePath(); - boolean active = app.getSelectedGpxHelper().getSelectedFileByPath(absolutePath) != null; - long modifiedTime = dataItem.getParameter(FILE_LAST_MODIFIED_TIME); - long fileSize = file.length(); - Integer color = dataItem.getParameter(COLOR); - String colorName = ""; - if (color != null) { - colorName = GpxAppearanceAdapter.parseTrackColorName(app.getRendererRegistry().getCurrentSelectedRenderer(), color); - } - net.osmand.aidlapi.gpx.AGpxFileDetails details = null; - GpxTrackAnalysis analysis = dataItem.getAnalysis(); - if (analysis != null) { - details = createGpxFileDetailsV2(analysis); - } - net.osmand.aidlapi.gpx.AGpxFile gpxFile = new net.osmand.aidlapi.gpx.AGpxFile(fileName, modifiedTime, fileSize, active, colorName, details); - gpxFile.setRelativePath(GpxUiHelper.getGpxFileRelativePath(app, absolutePath)); - - files.add(gpxFile); - } + KFile file = dataItem.getFile(); + String fileName = file.name(); + String absolutePath = file.absolutePath(); + boolean active = app.getSelectedGpxHelper().getSelectedFileByPath(absolutePath) != null; + long modifiedTime = dataItem.getParameter(FILE_LAST_MODIFIED_TIME); + long fileSize = file.length(); + Integer color = dataItem.getParameter(COLOR); + String colorName = ""; + if (color != null) { + colorName = GpxAppearanceAdapter.parseTrackColorName(app.getRendererRegistry().getCurrentSelectedRenderer(), color); + } + net.osmand.aidlapi.gpx.AGpxFileDetails details = null; + GpxTrackAnalysis analysis = dataItem.getAnalysis(); + if (analysis != null) { + details = createGpxFileDetailsV2(analysis); + } + net.osmand.aidlapi.gpx.AGpxFile gpxFile = new net.osmand.aidlapi.gpx.AGpxFile(fileName, modifiedTime, fileSize, active, colorName, details); + gpxFile.setRelativePath(GpxUiHelper.getGpxFileRelativePath(app, absolutePath)); + + files.add(gpxFile); } return true; } boolean getImportedGpx(List files) { - List gpxDataItems = app.getGpxDbHelper().getItemsBlocking(); + List gpxDataItems = app.getGpxDbHelper().getItems(); for (GpxDataItem dataItem : gpxDataItems) { - File file = SharedUtil.jFile(dataItem.getFile()); - if (file.exists()) { - String fileName = file.getName(); - boolean active = app.getSelectedGpxHelper().getSelectedFileByPath(file.getAbsolutePath()) != null; - long modifiedTime = dataItem.getParameter(FILE_LAST_MODIFIED_TIME); - long fileSize = file.length(); - AGpxFileDetails details = null; - GpxTrackAnalysis analysis = dataItem.getAnalysis(); - if (analysis != null) { - details = createGpxFileDetails(analysis); - } - files.add(new AGpxFile(fileName, modifiedTime, fileSize, active, details)); - } + KFile file = dataItem.getFile(); + String fileName = file.name(); + boolean active = app.getSelectedGpxHelper().getSelectedFileByPath(file.absolutePath()) != null; + long modifiedTime = dataItem.getParameter(FILE_LAST_MODIFIED_TIME); + long fileSize = file.length(); + AGpxFileDetails details = null; + GpxTrackAnalysis analysis = dataItem.getAnalysis(); + if (analysis != null) { + details = createGpxFileDetails(analysis); + } + files.add(new AGpxFile(fileName, modifiedTime, fileSize, active, details)); } return true; } String getGpxColor(String gpxFileName) { - List gpxDataItems = app.getGpxDbHelper().getItemsBlocking(); + List gpxDataItems = app.getGpxDbHelper().getItems(); for (GpxDataItem dataItem : gpxDataItems) { - File file = SharedUtil.jFile(dataItem.getFile()); - if (file.exists()) { - if (file.getName().equals(gpxFileName)) { - Integer color = dataItem.getParameter(COLOR); - if (color != null) { - return GpxAppearanceAdapter.parseTrackColorName(app.getRendererRegistry().getCurrentSelectedRenderer(), color); - } + KFile file = dataItem.getFile(); + if (file.name().equals(gpxFileName)) { + Integer color = dataItem.getParameter(COLOR); + if (color != null) { + return GpxAppearanceAdapter.parseTrackColorName(app.getRendererRegistry().getCurrentSelectedRenderer(), color); } } } diff --git a/OsmAnd/src/net/osmand/plus/auto/screens/TracksFoldersScreen.kt b/OsmAnd/src/net/osmand/plus/auto/screens/TracksFoldersScreen.kt index e72d8cfa781..10ccde8c56d 100644 --- a/OsmAnd/src/net/osmand/plus/auto/screens/TracksFoldersScreen.kt +++ b/OsmAnd/src/net/osmand/plus/auto/screens/TracksFoldersScreen.kt @@ -63,8 +63,7 @@ class TracksFoldersScreen( private fun reloadTracks() { val folder = TrackFolder(FileUtils.getExistingDir(app, GPX_INDEX_DIR).kFile(), null) - asyncLoader = TrackFolderLoaderTask(folder, this, true) - asyncLoader!!.execute() + asyncLoader = TrackFolderLoaderTask(folder, this).apply { execute() } } diff --git a/OsmAnd/src/net/osmand/plus/configmap/tracks/TracksTabsFragment.java b/OsmAnd/src/net/osmand/plus/configmap/tracks/TracksTabsFragment.java index 9b765cddb21..12174dc0de6 100644 --- a/OsmAnd/src/net/osmand/plus/configmap/tracks/TracksTabsFragment.java +++ b/OsmAnd/src/net/osmand/plus/configmap/tracks/TracksTabsFragment.java @@ -458,7 +458,7 @@ public void deleteTracks(@Nullable Set trackItems) { DeleteTracksTask deleteFilesTask = new DeleteTracksTask(app, trackItems, null, new GpxFilesDeletionListener() { @Override public void onGpxFilesDeletionFinished() { - reloadTracks(true); + reloadTracks(); } }); deleteFilesTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); @@ -469,7 +469,7 @@ public void onFileMove(@Nullable File src, @NonNull File dest) { if (dest.exists()) { app.showToastMessage(R.string.file_with_name_already_exists); } else if (src != null && FileUtils.renameGpxFile(app, src, dest) != null) { - reloadTracks(true); + reloadTracks(); } else { app.showToastMessage(R.string.file_can_not_be_moved); } @@ -477,7 +477,7 @@ public void onFileMove(@Nullable File src, @NonNull File dest) { @Override public void fileRenamed(@NonNull File src, @NonNull File dest) { - reloadTracks(true); + reloadTracks(); } public static void showInstance(@NonNull FragmentManager manager) { diff --git a/OsmAnd/src/net/osmand/plus/mapmarkers/MapMarkersHelper.java b/OsmAnd/src/net/osmand/plus/mapmarkers/MapMarkersHelper.java index baeeee6f596..829da184d14 100644 --- a/OsmAnd/src/net/osmand/plus/mapmarkers/MapMarkersHelper.java +++ b/OsmAnd/src/net/osmand/plus/mapmarkers/MapMarkersHelper.java @@ -325,8 +325,7 @@ private void updateGpxShowAsMarkers(@NonNull File file) { GpxDbHelper gpxDbHelper = ctx.getGpxDbHelper(); GpxDataItem dataItem = gpxDbHelper.getItem(SharedUtil.kFile(file)); if (dataItem != null) { - dataItem.setParameter(SHOW_AS_MARKERS, true); - gpxDbHelper.updateDataItem(dataItem); + gpxDbHelper.updateDataItemParameter(dataItem, SHOW_AS_MARKERS, true); } } diff --git a/OsmAnd/src/net/osmand/plus/myplaces/tracks/SearchMyPlacesTracksFragment.java b/OsmAnd/src/net/osmand/plus/myplaces/tracks/SearchMyPlacesTracksFragment.java index 172f39c5763..492bc5fc128 100644 --- a/OsmAnd/src/net/osmand/plus/myplaces/tracks/SearchMyPlacesTracksFragment.java +++ b/OsmAnd/src/net/osmand/plus/myplaces/tracks/SearchMyPlacesTracksFragment.java @@ -171,7 +171,7 @@ public void onDismiss(@NonNull DialogInterface dialog) { private void reloadTracks() { TrackFoldersHelper foldersHelper = getTrackFoldersHelper(); if (foldersHelper != null) { - foldersHelper.reloadTracks(true); + foldersHelper.reloadTracks(); } } diff --git a/OsmAnd/src/net/osmand/plus/myplaces/tracks/TrackFoldersHelper.java b/OsmAnd/src/net/osmand/plus/myplaces/tracks/TrackFoldersHelper.java index 2afadfc8405..0a171f2df84 100644 --- a/OsmAnd/src/net/osmand/plus/myplaces/tracks/TrackFoldersHelper.java +++ b/OsmAnd/src/net/osmand/plus/myplaces/tracks/TrackFoldersHelper.java @@ -125,6 +125,10 @@ public void setGpxImportListener(@Nullable GpxImportListener gpxImportListener) this.gpxImportListener = gpxImportListener; } + public void reloadTracks() { + reloadTracks(false); + } + public void reloadTracks(boolean forceLoad) { if (asyncLoader != null) { asyncLoader.cancel(); @@ -438,7 +442,7 @@ public void deleteTracks(@Nullable Set trackItems, @Nullable Set { - reloadTracks(); + reloadTracks(true); swipeRefresh.setRefreshing(false); }); } @@ -137,7 +137,7 @@ public void onResume() { smartFolderHelper.addUpdateListener(this); if (!trackFoldersHelper.isImporting()) { if (rootFolder.isEmpty() && !trackFoldersHelper.isLoadingTracks()) { - reloadTracks(false); + reloadTracks(); } else { updateContent(); } diff --git a/OsmAnd/src/net/osmand/plus/myplaces/tracks/dialogs/BaseTrackFolderFragment.java b/OsmAnd/src/net/osmand/plus/myplaces/tracks/dialogs/BaseTrackFolderFragment.java index 1d3c5633db1..b96ac453ba1 100644 --- a/OsmAnd/src/net/osmand/plus/myplaces/tracks/dialogs/BaseTrackFolderFragment.java +++ b/OsmAnd/src/net/osmand/plus/myplaces/tracks/dialogs/BaseTrackFolderFragment.java @@ -432,7 +432,7 @@ public void onTrackFolderAdd(String folderName) { dir.mkdirs(); dir.setLastModified(System.currentTimeMillis()); } - reloadTracks(); + reloadTracks(true); } @Override @@ -483,7 +483,7 @@ public void onTrackItemsSelected(@NonNull Set trackItems, boolean sel } protected void reloadTracks() { - reloadTracks(true); + reloadTracks(false); } protected void reloadTracks(boolean forceLoad) { diff --git a/OsmAnd/src/net/osmand/plus/myplaces/tracks/dialogs/SmartFolderFragment.kt b/OsmAnd/src/net/osmand/plus/myplaces/tracks/dialogs/SmartFolderFragment.kt index ead1555f696..85abcaa70bb 100644 --- a/OsmAnd/src/net/osmand/plus/myplaces/tracks/dialogs/SmartFolderFragment.kt +++ b/OsmAnd/src/net/osmand/plus/myplaces/tracks/dialogs/SmartFolderFragment.kt @@ -66,7 +66,7 @@ class SmartFolderFragment : TrackFolderFragment(), SmartFolderUpdateListener, .setTitleId(R.string.shared_string_refresh) .setIcon(uiUtilities.getThemedIcon(R.drawable.ic_action_update)) .setOnClickListener { - reloadTracks() + reloadTracks(true) } .showTopDivider(true) .create()) diff --git a/OsmAnd/src/net/osmand/plus/myplaces/tracks/dialogs/TrackFolderFragment.java b/OsmAnd/src/net/osmand/plus/myplaces/tracks/dialogs/TrackFolderFragment.java index cd7ad905150..5c4a7865113 100644 --- a/OsmAnd/src/net/osmand/plus/myplaces/tracks/dialogs/TrackFolderFragment.java +++ b/OsmAnd/src/net/osmand/plus/myplaces/tracks/dialogs/TrackFolderFragment.java @@ -101,7 +101,7 @@ private void setupSwipeRefresh(@NonNull View view) { SwipeRefreshLayout swipeRefresh = view.findViewById(R.id.swipe_refresh); swipeRefresh.setColorSchemeColors(ContextCompat.getColor(app, nightMode ? R.color.osmand_orange_dark : R.color.osmand_orange)); swipeRefresh.setOnRefreshListener(() -> { - reloadTracks(); + reloadTracks(true); swipeRefresh.setRefreshing(false); }); } diff --git a/OsmAnd/src/net/osmand/plus/settings/backend/backup/exporttype/TracksExportType.java b/OsmAnd/src/net/osmand/plus/settings/backend/backup/exporttype/TracksExportType.java index f05e5049031..8d4b38f8df9 100644 --- a/OsmAnd/src/net/osmand/plus/settings/backend/backup/exporttype/TracksExportType.java +++ b/OsmAnd/src/net/osmand/plus/settings/backend/backup/exporttype/TracksExportType.java @@ -36,11 +36,10 @@ public int getIconId() { @Override public List fetchExportData(@NonNull OsmandApplication app, boolean offlineBackup) { List files = new ArrayList<>(); - List gpxItems = app.getGpxDbHelper().getItemsBlocking(); + List gpxItems = app.getGpxDbHelper().getItems(); for (GpxDataItem item : gpxItems) { - File file = SharedUtil.jFile(item.getFile()); - if (file.exists() && !file.isDirectory()) { - files.add(file); + if (!item.getFile().isDirectory()) { + files.add(SharedUtil.jFile(item.getFile())); } } return files; diff --git a/OsmAnd/src/net/osmand/plus/shared/SharedUtil.kt b/OsmAnd/src/net/osmand/plus/shared/SharedUtil.kt index 6094d1db896..b32f32c71e5 100644 --- a/OsmAnd/src/net/osmand/plus/shared/SharedUtil.kt +++ b/OsmAnd/src/net/osmand/plus/shared/SharedUtil.kt @@ -7,6 +7,8 @@ import net.osmand.gpx.GPXUtilities import net.osmand.shared.KException import net.osmand.shared.data.KLatLon import net.osmand.shared.data.KQuadRect +import net.osmand.shared.extensions.jFile +import net.osmand.shared.extensions.kFile import net.osmand.shared.gpx.GpxFile import net.osmand.shared.gpx.GpxParameter import net.osmand.shared.gpx.GpxUtilities @@ -57,14 +59,10 @@ object SharedUtil { } @JvmStatic - fun kFile(file: File): KFile { - return KFile(file.absolutePath) - } + fun kFile(file: File): KFile = file.kFile() @JvmStatic - fun jFile(file: KFile): File { - return File(file.absolutePath()) - } + fun jFile(file: KFile): File = file.jFile() @JvmStatic fun kException(e: Exception): KException { @@ -405,6 +403,7 @@ object SharedUtil { @JvmStatic fun kGpxFile(gpxFile: GPXFile): GpxFile { val kGpxFile = GpxFile(gpxFile.author) + kGpxFile.path = gpxFile.path if (gpxFile.metadata != null) { kGpxFile.metadata = kMetadata(gpxFile.metadata) } diff --git a/OsmAnd/src/net/osmand/plus/track/BaseTracksTabsFragment.java b/OsmAnd/src/net/osmand/plus/track/BaseTracksTabsFragment.java index 28c50c9d3ce..fa30aa525e9 100644 --- a/OsmAnd/src/net/osmand/plus/track/BaseTracksTabsFragment.java +++ b/OsmAnd/src/net/osmand/plus/track/BaseTracksTabsFragment.java @@ -214,7 +214,7 @@ public void onResume() { setTabs(tabs); } if (asyncLoader == null) { - reloadTracks(false); + reloadTracks(); } gpxSelectionHelper.addListener(this); } @@ -225,10 +225,10 @@ public void onPause() { gpxSelectionHelper.removeListener(this); } - protected void reloadTracks(boolean forceLoad) { + protected void reloadTracks() { File gpxDir = FileUtils.getExistingDir(app, GPX_INDEX_DIR); TrackFolder folder = new TrackFolder(SharedUtil.kFile(gpxDir), null); - asyncLoader = new TrackFolderLoaderTask(folder, this, forceLoad); + asyncLoader = new TrackFolderLoaderTask(folder, this, false); asyncLoader.execute(); } diff --git a/OsmAnd/src/net/osmand/plus/track/fragments/controller/TrackColorController.java b/OsmAnd/src/net/osmand/plus/track/fragments/controller/TrackColorController.java index 854e0e29587..9e3df603896 100644 --- a/OsmAnd/src/net/osmand/plus/track/fragments/controller/TrackColorController.java +++ b/OsmAnd/src/net/osmand/plus/track/fragments/controller/TrackColorController.java @@ -200,12 +200,11 @@ protected ColoringType[] getSupportedColoringTypes() { } public static void saveCustomColorsToTracks(@NonNull OsmandApplication app, int prevColor, int newColor) { GpxDbHelper gpxDbHelper = app.getGpxDbHelper(); - List gpxDataItems = gpxDbHelper.getItemsBlocking(); + List gpxDataItems = gpxDbHelper.getItems(); for (GpxDataItem dataItem : gpxDataItems) { Integer color = dataItem.getParameter(COLOR); if (Algorithms.objectEquals(prevColor, color)) { - dataItem.setParameter(COLOR, newColor); - gpxDbHelper.updateDataItem(dataItem); + gpxDbHelper.updateDataItemParameter(dataItem, COLOR, newColor); } } List files = app.getSelectedGpxHelper().getSelectedGPXFiles(); diff --git a/OsmAnd/src/net/osmand/plus/track/helpers/TrackDisplayHelper.java b/OsmAnd/src/net/osmand/plus/track/helpers/TrackDisplayHelper.java index 469057860c7..2380684e879 100644 --- a/OsmAnd/src/net/osmand/plus/track/helpers/TrackDisplayHelper.java +++ b/OsmAnd/src/net/osmand/plus/track/helpers/TrackDisplayHelper.java @@ -95,9 +95,7 @@ public QuadRect getRect() { public boolean setJoinSegments(boolean joinSegments) { if (gpxDataItem != null) { - gpxDataItem.setParameter(JOIN_SEGMENTS, joinSegments); - boolean updated = app.getGpxDbHelper().updateDataItem(gpxDataItem); - + boolean updated = app.getGpxDbHelper().updateDataItemParameter(gpxDataItem, JOIN_SEGMENTS, joinSegments); SelectedGpxFile selectedGpxFile = app.getSelectedGpxHelper().getSelectedFileByPath(gpxFile.getPath()); if (updated && selectedGpxFile != null) { selectedGpxFile.setJoinSegments(joinSegments); diff --git a/OsmAnd/src/net/osmand/plus/views/layers/GPXLayer.java b/OsmAnd/src/net/osmand/plus/views/layers/GPXLayer.java index 78df0c9fa1d..b0aff004766 100644 --- a/OsmAnd/src/net/osmand/plus/views/layers/GPXLayer.java +++ b/OsmAnd/src/net/osmand/plus/views/layers/GPXLayer.java @@ -1321,8 +1321,7 @@ private String getAvailableOrDefaultColoringType(SelectedGpxFile selectedGpxFile return coloringType.getName(routeInfoAttribute); } else { if (!isCurrentTrack) { - dataItem.setParameter(COLORING_TYPE, defaultColoringType); - gpxDbHelper.updateDataItem(dataItem); + gpxDbHelper.updateDataItemParameter(dataItem, COLORING_TYPE, defaultColoringType); } return defaultColoringType; }