From b23552b3de6bf36c929103ce989bf8010378d092 Mon Sep 17 00:00:00 2001 From: Armin Date: Thu, 26 Oct 2023 10:49:55 +0200 Subject: [PATCH] Add locationTimestamp to File table --- .../de.cyface.persistence.Database/19.json | 12 ++++++++--- .../de/cyface/persistence/DatabaseMigrator.kt | 2 +- .../cyface/persistence/content/FileTable.kt | 9 +++++++++ .../de/cyface/persistence/model/File.kt | 7 ++++++- .../persistence/model/ParcelableFile.kt | 20 ++++++++++++++++++- 5 files changed, 44 insertions(+), 6 deletions(-) diff --git a/persistence/schemas/de.cyface.persistence.Database/19.json b/persistence/schemas/de.cyface.persistence.Database/19.json index 63351b57b..418a33f27 100644 --- a/persistence/schemas/de.cyface.persistence.Database/19.json +++ b/persistence/schemas/de.cyface.persistence.Database/19.json @@ -2,7 +2,7 @@ "formatVersion": 1, "database": { "version": 19, - "identityHash": "dbaa3857fac51d3902eb4f124f578417", + "identityHash": "150b3be3f34c7ca7d73037489f8f07af", "entities": [ { "tableName": "Identifier", @@ -298,7 +298,7 @@ }, { "tableName": "File", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `timestamp` INTEGER NOT NULL, `status` TEXT NOT NULL, `type` TEXT NOT NULL, `fileFormatVersion` INTEGER NOT NULL, `size` INTEGER NOT NULL, `path` TEXT NOT NULL, `lat` REAL, `lon` REAL, `measurementId` INTEGER NOT NULL, FOREIGN KEY(`measurementId`) REFERENCES `Measurement`(`_id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `timestamp` INTEGER NOT NULL, `status` TEXT NOT NULL, `type` TEXT NOT NULL, `fileFormatVersion` INTEGER NOT NULL, `size` INTEGER NOT NULL, `path` TEXT NOT NULL, `lat` REAL, `lon` REAL, `locationTimestamp` INTEGER, `measurementId` INTEGER NOT NULL, FOREIGN KEY(`measurementId`) REFERENCES `Measurement`(`_id`) ON UPDATE NO ACTION ON DELETE CASCADE )", "fields": [ { "fieldPath": "id", @@ -354,6 +354,12 @@ "affinity": "REAL", "notNull": false }, + { + "fieldPath": "locationTimestamp", + "columnName": "locationTimestamp", + "affinity": "INTEGER", + "notNull": false + }, { "fieldPath": "measurementId", "columnName": "measurementId", @@ -396,7 +402,7 @@ "views": [], "setupQueries": [ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'dbaa3857fac51d3902eb4f124f578417')" + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '150b3be3f34c7ca7d73037489f8f07af')" ] } } \ No newline at end of file diff --git a/persistence/src/main/kotlin/de/cyface/persistence/DatabaseMigrator.kt b/persistence/src/main/kotlin/de/cyface/persistence/DatabaseMigrator.kt index 37917cedf..19568cf4b 100644 --- a/persistence/src/main/kotlin/de/cyface/persistence/DatabaseMigrator.kt +++ b/persistence/src/main/kotlin/de/cyface/persistence/DatabaseMigrator.kt @@ -101,7 +101,7 @@ class DatabaseMigrator(val context: Context) { "`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `timestamp` INTEGER NOT NULL, " + "`status` TEXT NOT NULL, `type` TEXT NOT NULL, `fileFormatVersion` INTEGER NOT NULL, " + "`size` INTEGER NOT NULL, `path` TEXT NOT NULL, " + - "`lat` REAL, `lon` REAL, `measurementId` INTEGER NOT NULL, " + + "`lat` REAL, `lon` REAL, `locationTimestamp` INTEGER, `measurementId` INTEGER NOT NULL, " + "FOREIGN KEY(`measurementId`) REFERENCES `Measurement`(`_id`) " + "ON UPDATE NO ACTION ON DELETE CASCADE )") database.execSQL("CREATE INDEX IF NOT EXISTS `index_File_measurementId` ON `File` (`measurementId`)") diff --git a/persistence/src/main/kotlin/de/cyface/persistence/content/FileTable.kt b/persistence/src/main/kotlin/de/cyface/persistence/content/FileTable.kt index db309bfe3..cf4ceed68 100644 --- a/persistence/src/main/kotlin/de/cyface/persistence/content/FileTable.kt +++ b/persistence/src/main/kotlin/de/cyface/persistence/content/FileTable.kt @@ -92,6 +92,14 @@ class FileTable : AbstractCyfaceTable(URI_PATH) { */ const val COLUMN_LON = "lon" + /** + * Column name for the column storing the Unix timestamp in milliseconds of the last known location. + * + * It allows to identify when the last known location is from too long. Additionally, it's the + * link to the location data, e.g. to get additional data like the accuracy. + */ + const val COLUMN_LOCATION_TIMESTAMP = "location_timestamp" + /** * Returns the URI which identifies the table represented by this class. * @@ -116,6 +124,7 @@ class FileTable : AbstractCyfaceTable(URI_PATH) { COLUMN_PATH, COLUMN_LAT, COLUMN_LON, + COLUMN_LOCATION_TIMESTAMP, BaseColumns.MEASUREMENT_ID ) } \ No newline at end of file diff --git a/persistence/src/main/kotlin/de/cyface/persistence/model/File.kt b/persistence/src/main/kotlin/de/cyface/persistence/model/File.kt index 7a032513d..b3b3cae81 100644 --- a/persistence/src/main/kotlin/de/cyface/persistence/model/File.kt +++ b/persistence/src/main/kotlin/de/cyface/persistence/model/File.kt @@ -58,8 +58,9 @@ data class File( override val path: Path, override val lat: Double?, override val lon: Double?, + override val locationTimestamp: Long?, @ColumnInfo(index = true) val measurementId: Long -) : ParcelableFile(timestamp, status, type, fileFormatVersion, size, path, lat, lon) { +) : ParcelableFile(timestamp, status, type, fileFormatVersion, size, path, lat, lon, locationTimestamp) { /** * Creates a new instance of this class which was not yet persisted and has [id] set to `0`. @@ -74,6 +75,7 @@ data class File( * by Android: https://developer.android.com/training/data-storage/app-specific * @param lat The latitude of the last known location, e.g. 51.123, or null if unknown. * @param lon The longitude of the last known location, e.g. 13.123, or null if unknown. + * @param locationTimestamp The timestamp of the last known location, or null if unknown. * @param measurementId The device-unique id of the measurement this data point belongs to. */ constructor( @@ -85,6 +87,7 @@ data class File( path: Path, lat: Double?, lon: Double?, + locationTimestamp: Long?, measurementId: Long ) : this( 0, @@ -96,6 +99,7 @@ data class File( path, lat, lon, + locationTimestamp, measurementId ) @@ -119,6 +123,7 @@ data class File( if (path != other.path) return false if (lat != other.lat) return false if (lon != other.lon) return false + if (locationTimestamp != other.locationTimestamp) return false if (measurementId != other.measurementId) return false return true diff --git a/persistence/src/main/kotlin/de/cyface/persistence/model/ParcelableFile.kt b/persistence/src/main/kotlin/de/cyface/persistence/model/ParcelableFile.kt index 49b18ddf5..08e77ab06 100644 --- a/persistence/src/main/kotlin/de/cyface/persistence/model/ParcelableFile.kt +++ b/persistence/src/main/kotlin/de/cyface/persistence/model/ParcelableFile.kt @@ -93,6 +93,15 @@ open class ParcelableFile : DataPoint { */ open val lon: Double? + /** + * Column name for the column storing the Unix timestamp in milliseconds of the last known location, + * or null if unknown. + * + * It allows to identify when the last known location is from too long. Additionally, it's the + * link to the location data, e.g. to get additional data like the accuracy. + */ + open val locationTimestamp: Long? + /** * Creates a new completely initialized instance of this class. * @@ -106,6 +115,7 @@ open class ParcelableFile : DataPoint { * by Android: https://developer.android.com/training/data-storage/app-specific * @param lat The latitude of the last known location, e.g. 51.123, or null if unknown. * @param lon The longitude of the last known location, e.g. 13.123, or null if unknown. + * @param locationTimestamp The timestamp of the last known location, or null if unknown. */ constructor( timestamp: Long, @@ -115,7 +125,8 @@ open class ParcelableFile : DataPoint { size: Long, path: Path, lat: Double?, - lon: Double? + lon: Double?, + locationTimestamp: Long? ) : super(timestamp) { require(timestamp >= 0L) { "Illegal argument: timestamp was less than 0L!" } require(type != FileType.FILE_TYPE_UNSPECIFIED) { "Unsupported type $type." } @@ -131,6 +142,9 @@ open class ParcelableFile : DataPoint { "Illegal value for longitude. Is required to be between -180.0 and 180.0 but was $lon." } } + if (locationTimestamp != null) { + require(locationTimestamp >= 0L) { "Illegal argument: locationTimestamp was less than 0L!" } + } this.status = status this.type = type this.fileFormatVersion = fileFormatVersion @@ -138,6 +152,7 @@ open class ParcelableFile : DataPoint { this.path = path this.lat = lat this.lon = lon + this.locationTimestamp = locationTimestamp } /* * MARK: Parcelable Interface @@ -155,6 +170,7 @@ open class ParcelableFile : DataPoint { path = Paths.get(`in`.readString()) // supported < API 26 with NIO enabled desugaring lat = `in`.readValue(Double::class.java.classLoader) as? Double lon = `in`.readValue(Double::class.java.classLoader) as? Double + locationTimestamp = `in`.readValue(Long::class.java.classLoader) as? Long } override fun describeContents(): Int { @@ -170,6 +186,7 @@ open class ParcelableFile : DataPoint { dest.writeString(path.toString()) dest.writeValue(lat) // Handle nullable Double dest.writeValue(lon) // Handle nullable Double + dest.writeValue(locationTimestamp) // Handle nullable Long } override fun equals(other: Any?): Boolean { @@ -186,6 +203,7 @@ open class ParcelableFile : DataPoint { if (path != other.path) return false if (lat != other.lat) return false if (lon != other.lon) return false + if (locationTimestamp != other.locationTimestamp) return false return true }