From 4dba706f2f7879d9efd7420e909500f793f548d4 Mon Sep 17 00:00:00 2001 From: Hossain Khan Date: Sat, 16 Mar 2024 08:03:13 -0400 Subject: [PATCH 1/6] [ADDED] Semantic timeline parser testing. Updated `nullable` properties. --- parser/src/main/kotlin/model/Semantic.kt | 55 +++++++++++++----------- sample/src/main/kotlin/Main.kt | 28 +++++++++--- 2 files changed, 54 insertions(+), 29 deletions(-) diff --git a/parser/src/main/kotlin/model/Semantic.kt b/parser/src/main/kotlin/model/Semantic.kt index 22f9119..93b0681 100644 --- a/parser/src/main/kotlin/model/Semantic.kt +++ b/parser/src/main/kotlin/model/Semantic.kt @@ -54,7 +54,7 @@ data class ActivitySegment( * Example: "IN_BUS" */ @Json(name = "activityType") - val activityType: String, + val activityType: String?, /** * List of all the considered candidate activity types and their probabilities. The sum of all the probabilities is always <= 100. * Example: [Activity(activityType = "IN_BUS", probability = 85.6847882270813), Activity(activityType = "WALKING", probability = 8.418431878089905)] @@ -66,7 +66,7 @@ data class ActivitySegment( * Example: "HIGH" */ @Json(name = "confidence") - val confidence: String, + val confidence: String?, @Json(name = "waypointPath") val waypointPath: WaypointPath?, /** The simplified raw path of the activity */ @@ -142,12 +142,12 @@ data class Location( * Latitude coordinate of the location. Degrees multiplied by 10^7 and rounded to the nearest integer. * Example: 414216106 */ - @Json(name = "latitudeE7") val latitudeE7: Int, + @Json(name = "latitudeE7") val latitudeE7: Int?, /** * Longitude coordinate of the location. Degrees multiplied by 10^7 and rounded to the nearest integer. * Example: 21684775 */ - @Json(name = "longitudeE7") val longitudeE7: Int, + @Json(name = "longitudeE7") val longitudeE7: Int?, /** * Google Maps Place ID of the location. * Example: "ChIJk_s92NyipBIRUMnDG8Kq2Js" @@ -236,6 +236,13 @@ enum class SemanticType(val title: String, val description: String, val extraCol "The place has been given a private label by the user.", "#03a9f4", ), + + @Json(name = "TYPE_UNKNOWN") + TYPE_UNKNOWN( + "Type Unknown", + "The place has not been categorized.", + "#03a9f4", + ), } /** @@ -270,43 +277,43 @@ data class PlaceVisit( * Example: 414216106 */ @Json(name = "centerLatE7") - val centerLatE7: Int, + val centerLatE7: Int?, /** * Longitude coordinate of the location. Degrees multiplied by 10^7 and rounded to the nearest integer, in the range -1800000000 to +1800000000 (divide value by 10^7 for the usual range -180° to +180°). * Example: 21684775 */ @Json(name = "centerLngE7") - val centerLngE7: Int, + val centerLngE7: Int?, /** * Duration of the place visit * Example: Duration(startTimestamp = "2022-03-06T14:13:11.092Z", endTimestamp = "2022-03-06T15:13:11.092Z") */ @Json(name = "duration") - val duration: Duration, + val duration: Duration?, /** * Categorized confidence for this place visit. One of: `LOW_CONFIDENCE`, `MEDIUM_CONFIDENCE`, `HIGH_CONFIDENCE` or `USER_CONFIRMED`. * Example: "HIGH" */ @Json(name = "placeConfidence") - val placeConfidence: String, + val placeConfidence: String?, /** * Visit confidence for this place visit * Example: 95 */ @Json(name = "visitConfidence") - val visitConfidence: Int, + val visitConfidence: Int?, /** * Location confidence for this place visit * Example: 71 */ @Json(name = "locationConfidence") - val locationConfidence: Int, + val locationConfidence: Int?, /** * Other candidate locations for this place visit * Example: [Location(latitudeE7 = 414216106, longitudeE7 = 21684775, placeId = "ChIJk_s92NyipBIRUMnDG8Kq2Js")] */ @Json(name = "otherCandidateLocations") - val otherCandidateLocations: List, + val otherCandidateLocations: List = emptyList(), /** * Child visits for this place visit * Example: [PlaceVisit(location = Location(latitudeE7 = 414216106, longitudeE7 = 21684775, placeId = "ChIJk_s92NyipBIRUMnDG8Kq2Js"), centerLatE7 = 414216106, centerLngE7 = 21684775, duration = Duration(startTimestamp = "2022-03-06T14:13:11.092Z", endTimestamp = "2022-03-06T15:13:11.092Z"), placeConfidence = "HIGH", visitConfidence = 95, locationConfidence = 71, otherCandidateLocations = [Location(latitudeE7 = 414216106, longitudeE7 = 21684775, placeId = "ChIJk_s92NyipBIRUMnDG8Kq2Js")])] @@ -353,7 +360,7 @@ data class PlaceVisit( * Example: "SINGLE_PLACE" */ @Json(name = "placeVisitType") - val placeVisitType: String, + val placeVisitType: String?, /** * Place Visit Importance for this place visit. One of `MAIN` or `TRANSITIONAL`. * Example: "MAIN" @@ -439,30 +446,30 @@ data class TransitPath( * Example: "ChIJQVEUoLuipBIRJO37wI4yyBs" */ @Json(name = "linePlaceId") - val linePlaceId: String, + val linePlaceId: String?, /** * Time information (departure and arrival times, both real and scheduled) for each transit stop used. */ @Json(name = "stopTimesInfo") - val stopTimesInfo: List, + val stopTimesInfo: List = emptyList(), /** * Source of the location data of the transit path. Either `BACKFILLED` or `INFERRED`. * Example: "INFERRED" */ @Json(name = "source") - val source: String, + val source: String?, /** * Confidence level of the transit path data. Ranges from 0 to 1. * Example: 0.9155850640140931 */ @Json(name = "confidence") - val confidence: Double, + val confidence: Double?, /** * Distance traveled with the transit path, in meters. * Example: 2341.0 */ @Json(name = "distanceMeters") - val distanceMeters: Double, + val distanceMeters: Double?, ) @JsonClass(generateAdapter = true) @@ -614,10 +621,10 @@ data class OriginalCandidates( data class Checkin( /** The timestamp of the checkin */ @Json(name = "timestamp") - val timestamp: String, + val timestamp: String?, /** The place ID of the checkin */ @Json(name = "placeId") - val placeId: String, + val placeId: String?, ) /** @@ -660,25 +667,25 @@ data class WaypointPath( * Example: "INFERRED" */ @Json(name = "source") - val source: String, + val source: String?, /** * Total distance of the path, in meters. * Example: 396.34176716755843 */ @Json(name = "distanceMeters") - val distanceMeters: Double, + val distanceMeters: Double?, /** * Travel mode of the path. Can be `WALK`, `DRIVE`, or `BICYCLE`. * Example: "WALK" */ @Json(name = "travelMode") - val travelMode: String, + val travelMode: String?, /** * Confidence of the path. * Example: 0.7986568220419046 */ @Json(name = "confidence") - val confidence: Double, + val confidence: Double?, /** * Road segments of the path. * Example: [RoadSegment(duration = "8s", placeId = "ChIJk_s92NyipBIRUMnDG8Kq2Js")] @@ -694,7 +701,7 @@ data class RoadSegment( * Example: "8s" */ @Json(name = "duration") - val duration: String, + val duration: String?, /** * Google Maps Place ID of the location. * Example: "ChIJk_s92NyipBIRUMnDG8Kq2Js" diff --git a/sample/src/main/kotlin/Main.kt b/sample/src/main/kotlin/Main.kt index 7493323..b511b80 100644 --- a/sample/src/main/kotlin/Main.kt +++ b/sample/src/main/kotlin/Main.kt @@ -4,11 +4,29 @@ import java.io.File fun main() { println("Sample app for timeline project.") +// val parser = Parser() +// // load "Records.json" file +// val recordsJson = parser::class.java.classLoader.getResource("Records.json")?.readText()!! +// val records = parser.parseRecords(recordsJson) +// +// println("Got records: ${records.locations.size} records.") + println() + + parseSemanticRecords() +} + +fun parseSemanticRecords() { val parser = Parser() - // load "Records.json" file - val recordsJson = parser::class.java.classLoader.getResource("Records.json")?.readText()!! - val records = parser.parseRecords(recordsJson) - println("Got records: ${records.locations.size} records.") - println() + val directory = File("sample/src/main/resources/Location_History/2015/") + val files = directory.listFiles() + files?.forEach { + // List each files of directory + println("Parsing file: ${it.name}") + + val jsonText: String = it.readText() + val semanticTimeline = parser.parseSemanticTimeline(jsonText) + + println("Got timeline items: ${semanticTimeline.timelineObjects.size}") + } } From f83cfae77731f50ddbc5d4bd6bade94f1bdea9b7 Mon Sep 17 00:00:00 2001 From: Hossain Khan Date: Sat, 16 Mar 2024 08:15:17 -0400 Subject: [PATCH 2/6] [ADDED] Location data source enum --- parser/src/main/kotlin/model/Semantic.kt | 26 ++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/parser/src/main/kotlin/model/Semantic.kt b/parser/src/main/kotlin/model/Semantic.kt index 93b0681..43e7676 100644 --- a/parser/src/main/kotlin/model/Semantic.kt +++ b/parser/src/main/kotlin/model/Semantic.kt @@ -457,7 +457,7 @@ data class TransitPath( * Example: "INFERRED" */ @Json(name = "source") - val source: String?, + val source: DataSource?, /** * Confidence level of the transit path data. Ranges from 0 to 1. * Example: 0.9155850640140931 @@ -556,6 +556,28 @@ enum class LocationSource { UNKNOWN, } +/** + * Represents the source of the location data of the path. + * Example: "INFERRED" + */ +enum class DataSource { + + /** + * Indicates the location data of the path is backfilled. + */ + BACKFILLED, + + /** + * Indicates the location data of the path is inferred. + */ + INFERRED, + + /** + * Indicates the location data of the path is resnapped for edit. + */ + RESNAPPED_FOR_EDIT +} + /** * Represents the edit action metadata. */ @@ -667,7 +689,7 @@ data class WaypointPath( * Example: "INFERRED" */ @Json(name = "source") - val source: String?, + val source: DataSource?, /** * Total distance of the path, in meters. * Example: 396.34176716755843 From a03de477ce80d4e90a23f8c9651c08aa4f5e701c Mon Sep 17 00:00:00 2001 From: Hossain Khan Date: Sat, 16 Mar 2024 08:16:13 -0400 Subject: [PATCH 3/6] [MINOR] Format kotlin --- parser/src/main/kotlin/model/Semantic.kt | 3 +-- sample/src/main/kotlin/Main.kt | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/parser/src/main/kotlin/model/Semantic.kt b/parser/src/main/kotlin/model/Semantic.kt index 43e7676..ba37205 100644 --- a/parser/src/main/kotlin/model/Semantic.kt +++ b/parser/src/main/kotlin/model/Semantic.kt @@ -561,7 +561,6 @@ enum class LocationSource { * Example: "INFERRED" */ enum class DataSource { - /** * Indicates the location data of the path is backfilled. */ @@ -575,7 +574,7 @@ enum class DataSource { /** * Indicates the location data of the path is resnapped for edit. */ - RESNAPPED_FOR_EDIT + RESNAPPED_FOR_EDIT, } /** diff --git a/sample/src/main/kotlin/Main.kt b/sample/src/main/kotlin/Main.kt index b511b80..3694a51 100644 --- a/sample/src/main/kotlin/Main.kt +++ b/sample/src/main/kotlin/Main.kt @@ -18,7 +18,7 @@ fun main() { fun parseSemanticRecords() { val parser = Parser() - val directory = File("sample/src/main/resources/Location_History/2015/") + val directory = File("sample/src/main/resources/Location_History/2022/") val files = directory.listFiles() files?.forEach { // List each files of directory From a047f0f4014d59337cddff4e26bab728c2947425 Mon Sep 17 00:00:00 2001 From: Hossain Khan Date: Sat, 16 Mar 2024 08:20:06 -0400 Subject: [PATCH 4/6] [ADDED] Record location source --- parser/src/main/kotlin/model/Records.kt | 30 ++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/parser/src/main/kotlin/model/Records.kt b/parser/src/main/kotlin/model/Records.kt index 94df509..0bed5a8 100644 --- a/parser/src/main/kotlin/model/Records.kt +++ b/parser/src/main/kotlin/model/Records.kt @@ -75,7 +75,7 @@ data class LocationRecord( * Source (technology) that provided the location information for this record. * Common values are: `WIFI`, `CELL`, `GPS`, `UNKNOWN` (note: sometimes found in lowercase). */ - val source: String?, + val source: LocationRecordSource?, /** * Timestamp (as an ISO 8601 string) of the record. */ @@ -90,6 +90,34 @@ data class LocationRecord( val verticalAccuracy: Int?, ) +/** + * Represents the source (technology) that provided the location information for this record. + * Common values are: `WIFI`, `CELL`, `GPS`, `UNKNOWN` (note: sometimes found in lowercase). + * Example: "WIFI" + */ +enum class LocationRecordSource { + + /** + * Indicates the location information was provided by WIFI. + */ + WIFI, + + /** + * Indicates the location information was provided by CELL. + */ + CELL, + + /** + * Indicates the location information was provided by GPS. + */ + GPS, + + /** + * Indicates the location information was provided by UNKNOWN. + */ + UNKNOWN, +} + /** * Information about the access points found in a Wi-Fi scan done by the device. */ From e0a88894e3f5d78eac13a969474f5b29b1dfd716 Mon Sep 17 00:00:00 2001 From: Hossain Khan Date: Sat, 16 Mar 2024 08:23:14 -0400 Subject: [PATCH 5/6] [ADDED] 2 more enums to record location source --- parser/src/main/kotlin/model/Records.kt | 11 ++++++++++- sample/src/main/kotlin/Main.kt | 12 ++++++------ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/parser/src/main/kotlin/model/Records.kt b/parser/src/main/kotlin/model/Records.kt index 0bed5a8..973c3da 100644 --- a/parser/src/main/kotlin/model/Records.kt +++ b/parser/src/main/kotlin/model/Records.kt @@ -96,7 +96,6 @@ data class LocationRecord( * Example: "WIFI" */ enum class LocationRecordSource { - /** * Indicates the location information was provided by WIFI. */ @@ -112,6 +111,16 @@ enum class LocationRecordSource { */ GPS, + /** + * Indicates the location information was provided by visiting location (e.g. on arrival). + */ + VISIT_ARRIVAL, + + /** + * Indicates the location information was provided by visiting location (e.g. on departure). + */ + VISIT_DEPARTURE, + /** * Indicates the location information was provided by UNKNOWN. */ diff --git a/sample/src/main/kotlin/Main.kt b/sample/src/main/kotlin/Main.kt index 3694a51..b016a39 100644 --- a/sample/src/main/kotlin/Main.kt +++ b/sample/src/main/kotlin/Main.kt @@ -4,12 +4,12 @@ import java.io.File fun main() { println("Sample app for timeline project.") -// val parser = Parser() -// // load "Records.json" file -// val recordsJson = parser::class.java.classLoader.getResource("Records.json")?.readText()!! -// val records = parser.parseRecords(recordsJson) -// -// println("Got records: ${records.locations.size} records.") + val parser = Parser() + // load "Records.json" file + val recordsJson = parser::class.java.classLoader.getResource("Records.json")?.readText()!! + val records = parser.parseRecords(recordsJson) + + println("Got records: ${records.locations.size} records.") println() parseSemanticRecords() From 3821b5768ecf65f6c66844e229b922beb18061ed Mon Sep 17 00:00:00 2001 From: Hossain Khan Date: Sat, 16 Mar 2024 08:26:01 -0400 Subject: [PATCH 6/6] [FIXED] Tests --- .../kotlin/dev/hossain/timeline/model/RecordsTestCopilot.kt | 4 ++-- .../kotlin/dev/hossain/timeline/model/SemanticTimelineTest.kt | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/parser/src/test/kotlin/dev/hossain/timeline/model/RecordsTestCopilot.kt b/parser/src/test/kotlin/dev/hossain/timeline/model/RecordsTestCopilot.kt index 2ea6d1d..8c0eaf2 100644 --- a/parser/src/test/kotlin/dev/hossain/timeline/model/RecordsTestCopilot.kt +++ b/parser/src/test/kotlin/dev/hossain/timeline/model/RecordsTestCopilot.kt @@ -31,7 +31,7 @@ class RecordsTestCopilot { locationMetadata = listOf(), longitudeE7 = 1800000000, platformType = "ANDROID", - source = "GPS", + source = LocationRecordSource.GPS, timestamp = "2022-01-01T00:00:00Z", velocity = 10, verticalAccuracy = 10, @@ -50,7 +50,7 @@ class RecordsTestCopilot { assertTrue(locationRecord.locationMetadata!!.isEmpty()) assertEquals(1800000000, locationRecord.longitudeE7) assertEquals("ANDROID", locationRecord.platformType) - assertEquals("GPS", locationRecord.source) + assertEquals(LocationRecordSource.GPS, locationRecord.source) assertEquals("2022-01-01T00:00:00Z", locationRecord.timestamp) assertEquals(10, locationRecord.velocity) assertEquals(10, locationRecord.verticalAccuracy) diff --git a/parser/src/test/kotlin/dev/hossain/timeline/model/SemanticTimelineTest.kt b/parser/src/test/kotlin/dev/hossain/timeline/model/SemanticTimelineTest.kt index 5fe2cee..ed946b7 100644 --- a/parser/src/test/kotlin/dev/hossain/timeline/model/SemanticTimelineTest.kt +++ b/parser/src/test/kotlin/dev/hossain/timeline/model/SemanticTimelineTest.kt @@ -44,8 +44,8 @@ class SemanticTimelineTest { assertThat(placeVisit.childVisits).isNull() assertThat(placeVisit.sectionId).isNull() - assertThat(placeVisit.duration.startTimestamp.toString()).isEqualTo("2021-08-01T01:22:24Z") - assertThat(placeVisit.duration.endTimestamp.toString()).isEqualTo("2021-08-01T01:25:36Z") + assertThat(placeVisit.duration!!.startTimestamp.toString()).isEqualTo("2021-08-01T01:22:24Z") + assertThat(placeVisit.duration!!.endTimestamp.toString()).isEqualTo("2021-08-01T01:25:36Z") assertThat(placeVisit.placeConfidence).isEqualTo("HIGH_CONFIDENCE") }