Compare commits
	
		
			8 commits
		
	
	
		
			c6a0212fb8
			...
			a27b8713a9
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| a27b8713a9 | |||
| 42311b446b | |||
| 4e2beedaef | |||
| 33405cd063 | |||
| 37c5754a24 | |||
| b84185ea4e | |||
| 52dbae2f41 | |||
| 0fc6971d9d | 
					 6 changed files with 69 additions and 62 deletions
				
			
		|  | @ -9,23 +9,27 @@ import java.io.File | |||
| class Database(val trackbook: Trackbook) | ||||
| { | ||||
|     var ready: Boolean = false | ||||
|     var ready_at: Long = 0 | ||||
|     lateinit var file: File | ||||
|     lateinit var connection: SQLiteDatabase | ||||
| 
 | ||||
|     fun close() | ||||
|     { | ||||
|         Log.i("VOUSSOIR", "Database.close") | ||||
|         this.connection.close() | ||||
|         this.ready = false | ||||
|         this.ready_at = 0 | ||||
|         this.trackbook.call_database_changed_listeners() | ||||
|     } | ||||
| 
 | ||||
|     fun connect(file: File) | ||||
|     { | ||||
|         Log.i("VOUSSOIR", "Connecting to database " + file.absolutePath) | ||||
|         Log.i("VOUSSOIR", "Database.connect: " + file.absolutePath) | ||||
|         this.file = file | ||||
|         this.connection = openOrCreateDatabase(file, null) | ||||
|         this.initialize_tables() | ||||
|         this.ready = true | ||||
|         this.ready_at = System.currentTimeMillis() | ||||
|         Log.i("VOUSSOIR", "Database.open: Calling all listeners") | ||||
|     } | ||||
| 
 | ||||
|  | @ -52,29 +56,21 @@ class Database(val trackbook: Trackbook) | |||
|         this.connection.endTransaction() | ||||
|     } | ||||
| 
 | ||||
|     fun delete_trkpt(device_id: String, time: Long, commit: Boolean=false) | ||||
|     fun delete_trkpt(device_id: String, time: Long) | ||||
|     { | ||||
|         Log.i("VOUSSOIR", "Database.delete_trkpt") | ||||
|         begin_transaction() | ||||
|         connection.delete("trkpt", "device_id = ? AND time = ?", arrayOf(device_id, time.toString())) | ||||
|         if (commit) | ||||
|         { | ||||
|             this.commit() | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fun delete_trkpt_start_end(device_id: String, start_time: Long, end_time: Long, commit: Boolean=false) | ||||
|     fun delete_trkpt_start_end(device_id: String, start_time: Long, end_time: Long) | ||||
|     { | ||||
|         Log.i("VOUSSOIR", "Track.delete ${device_id} ${start_time} -- ${end_time}.") | ||||
|         this.begin_transaction() | ||||
|         this.connection.delete("trkpt", "device_id = ? AND time >= ? AND time <= ?", arrayOf(device_id, start_time.toString(), end_time.toString())) | ||||
|         if (commit) | ||||
|         { | ||||
|             this.commit() | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fun insert_trkpt(trkpt: Trkpt, commit: Boolean=false) | ||||
|     fun insert_trkpt(trkpt: Trkpt) | ||||
|     { | ||||
|         Log.i("VOUSSOIR", "Database.insert_trkpt") | ||||
|         val values = ContentValues().apply { | ||||
|  | @ -89,10 +85,6 @@ class Database(val trackbook: Trackbook) | |||
|         } | ||||
|         begin_transaction() | ||||
|         connection.insert("trkpt", null, values) | ||||
|         if (commit) | ||||
|         { | ||||
|             this.commit() | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fun select_trkpt_start_end(device_id: String, start_time: Long, end_time: Long, max_accuracy: Float=Keys.DEFAULT_MAX_ACCURACY, order: String="ASC"): Iterator<Trkpt> | ||||
|  | @ -156,18 +148,14 @@ class Database(val trackbook: Trackbook) | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fun delete_homepoint(id: Long, commit: Boolean=false) | ||||
|     fun delete_homepoint(id: Long) | ||||
|     { | ||||
|         Log.i("VOUSSOIR", "Database.delete_homepoint") | ||||
|         begin_transaction() | ||||
|         connection.delete("homepoints", "id = ?", arrayOf(id.toString())) | ||||
|         if (commit) | ||||
|         { | ||||
|             this.commit() | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fun insert_homepoint(id: Long, name: String, latitude: Double, longitude: Double, radius: Double, commit: Boolean=false) | ||||
|     fun insert_homepoint(id: Long, name: String, latitude: Double, longitude: Double, radius: Double) | ||||
|     { | ||||
|         Log.i("VOUSSOIR", "Database.insert_homepoint") | ||||
|         val values = ContentValues().apply { | ||||
|  | @ -179,13 +167,9 @@ class Database(val trackbook: Trackbook) | |||
|         } | ||||
|         begin_transaction() | ||||
|         connection.insert("homepoints", null, values) | ||||
|         if (commit) | ||||
|         { | ||||
|             this.commit() | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fun update_homepoint(id: Long, name: String, radius: Double, commit: Boolean=false) | ||||
|     fun update_homepoint(id: Long, name: String, radius: Double) | ||||
|     { | ||||
|         Log.i("VOUSSOIR", "Database.update_homepoint") | ||||
|         val values = ContentValues().apply { | ||||
|  | @ -194,13 +178,9 @@ class Database(val trackbook: Trackbook) | |||
|         } | ||||
|         begin_transaction() | ||||
|         connection.update("homepoints", values, "id = ?", arrayOf(id.toString())) | ||||
|         if (commit) | ||||
|         { | ||||
|             this.commit() | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fun update_trkpt(trkpt: Trkpt, commit: Boolean=false) | ||||
|     fun update_trkpt(trkpt: Trkpt) | ||||
|     { | ||||
|         Log.i("VOUSSOIR", "Database.update_trkpt") | ||||
|         val values = ContentValues().apply { | ||||
|  | @ -213,14 +193,11 @@ class Database(val trackbook: Trackbook) | |||
|         } | ||||
|         begin_transaction() | ||||
|         connection.update("trkpt", values, "device_id = ? AND time = ?", arrayOf(trkpt.device_id, trkpt.time.toString())) | ||||
|         if (commit) | ||||
|         { | ||||
|             this.commit() | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private fun initialize_tables() | ||||
|     { | ||||
|         Log.i("VOUSSOIR", "Database.initialize_tables") | ||||
|         begin_transaction() | ||||
|         this.connection.execSQL("CREATE TABLE IF NOT EXISTS meta(name TEXT PRIMARY KEY, value TEXT)") | ||||
|         this.connection.execSQL("CREATE TABLE IF NOT EXISTS trkpt(device_id INTEGER NOT NULL, time INTEGER NOT NULL, lat REAL NOT NULL, lon REAL NOT NULL, provider TEXT, accuracy REAL, ele INTEGER, sat INTEGER, PRIMARY KEY(device_id, time))") | ||||
|  |  | |||
|  | @ -168,8 +168,8 @@ class MapFragment : Fragment() | |||
|                         latitude=point.latitude, | ||||
|                         longitude=point.longitude, | ||||
|                         radius=radius, | ||||
|                         commit=true, | ||||
|                     ) | ||||
|                     trackbook.database.commit() | ||||
|                     trackbook.load_homepoints() | ||||
|                     create_homepoint_overlays() | ||||
|                     dialog.dismiss() | ||||
|  | @ -548,14 +548,16 @@ class MapFragment : Fragment() | |||
|                         val save_button: Button = dialog.findViewById(R.id.homepoint_save_button) | ||||
|                         delete_button.text = "Delete" | ||||
|                         delete_button.setOnClickListener { | ||||
|                             trackbook.database.delete_homepoint(homepoint.id, commit=true) | ||||
|                             trackbook.database.delete_homepoint(homepoint.id) | ||||
|                             trackbook.database.commit() | ||||
|                             trackbook.load_homepoints() | ||||
|                             create_homepoint_overlays() | ||||
|                             dialog.dismiss() | ||||
|                         } | ||||
|                         save_button.setOnClickListener { | ||||
|                             val radius = radius_input.text.toString().toDoubleOrNull() ?: 25.0 | ||||
|                             trackbook.database.update_homepoint(homepoint.id, name=name_input.text.toString(), radius=radius, commit=true) | ||||
|                             trackbook.database.update_homepoint(homepoint.id, name=name_input.text.toString(), radius=radius) | ||||
|                             trackbook.database.commit() | ||||
|                             trackbook.load_homepoints() | ||||
|                             create_homepoint_overlays() | ||||
|                             dialog.dismiss() | ||||
|  | @ -670,11 +672,12 @@ class MapFragment : Fragment() | |||
|                 state: ${state_name()} | ||||
|                 clock: ${iso8601_local_noms(System.currentTimeMillis())} | ||||
|              location: ${iso8601_local_noms(tracker.currentBestLocation.time)} | ||||
|              database: ${iso8601_local_noms(trackbook.database.ready_at)} | ||||
|             listeners: ${iso8601_local_noms(tracker.listeners_enabled_at)} | ||||
|                motion: ${iso8601_local_noms(tracker.last_significant_motion)} | ||||
|              watchdog: ${iso8601_local_noms(tracker.last_watchdog)} | ||||
|                  home: ${iso8601_local_noms(tracker.arrived_at_home)} | ||||
|                  died: ${iso8601_local_noms(tracker.gave_up_at)} | ||||
|                  died: ${iso8601_local_noms(tracker.dead_at)} | ||||
|                 power: ${tracker.device_is_charging} | ||||
|              wakelock: ${tracker.wakelock.isHeld} | ||||
|              accuracy: ${accuracy_text} m | ||||
|  |  | |||
|  | @ -97,8 +97,9 @@ data class Track ( | |||
|             xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd" | ||||
|         > | ||||
|         """.trimIndent()) | ||||
|         val name_escaped = this.name.replace("&", "&").replace("<", "<").replace(">", ">") | ||||
|         write("\t<metadata>") | ||||
|         write("\t\t<name>${this.name}</name>") | ||||
|         write("\t\t<name>${name_escaped}</name>") | ||||
|         write("\t\t<application>${BuildConfig.APPLICATION_ID} ${BuildConfig.VERSION_NAME}</application>") | ||||
|         write("\t\t<device>${this.device_id}</device>") | ||||
|         write("\t</metadata>") | ||||
|  |  | |||
|  | @ -271,7 +271,8 @@ class TrackFragment : Fragment(), MapListener, YesNoDialog.YesNoDialogListener | |||
|                 Log.i("VOUSSOIR", selected.rendered_by_polyline?.actualPoints?.size.toString()) | ||||
|                 selected.rendered_by_polyline?.setPoints(ArrayList(selected.rendered_by_polyline?.actualPoints)) | ||||
|                 Log.i("VOUSSOIR", selected.rendered_by_polyline?.actualPoints?.size.toString()) | ||||
|                 trackbook.database.delete_trkpt(selected.device_id, selected.time, commit=true) | ||||
|                 trackbook.database.delete_trkpt(selected.device_id, selected.time) | ||||
|                 trackbook.database.commit() | ||||
|                 deselect_trkpt() | ||||
|                 mapView.invalidate() | ||||
|             } | ||||
|  | @ -454,7 +455,10 @@ class TrackFragment : Fragment(), MapListener, YesNoDialog.YesNoDialogListener | |||
|             } | ||||
|             override fun onMarkerDragEnd(marker: Marker?) | ||||
|             { | ||||
|                 selected_trkpt?.let { trackbook.database.update_trkpt(it, commit=true) } | ||||
|                 selected_trkpt?.let { | ||||
|                     trackbook.database.update_trkpt(it) | ||||
|                     trackbook.database.commit() | ||||
|                 } | ||||
|             } | ||||
|         }) | ||||
| 
 | ||||
|  | @ -631,7 +635,8 @@ class TrackFragment : Fragment(), MapListener, YesNoDialog.YesNoDialogListener | |||
|                     mid_location.accuracy = 0f | ||||
|                     val mid_trkpt = Trkpt(trkpt.device_id, mid_location) | ||||
|                     deselect_trkpt() | ||||
|                     trackbook.database.insert_trkpt(mid_trkpt, commit=true) | ||||
|                     trackbook.database.insert_trkpt(mid_trkpt) | ||||
|                     trackbook.database.commit() | ||||
|                     requery_and_render.run() | ||||
|                     select_trkpt_by_timestamp(mid_trkpt.time) | ||||
|                     return | ||||
|  | @ -695,7 +700,7 @@ class TrackFragment : Fragment(), MapListener, YesNoDialog.YesNoDialogListener | |||
|             trkpt.latitude = new_location.latitude | ||||
|             trkpt.longitude = new_location.longitude | ||||
|             trkpt.altitude = a.altitude + (ele_span * proportion) | ||||
|             trackbook.database.update_trkpt(trkpt, commit=false) | ||||
|             trackbook.database.update_trkpt(trkpt) | ||||
|         } | ||||
|         trackbook.database.commit() | ||||
|     } | ||||
|  | @ -862,8 +867,8 @@ class TrackFragment : Fragment(), MapListener, YesNoDialog.YesNoDialogListener | |||
|                 track.device_id, | ||||
|                 track.trkpts.first().time, | ||||
|                 track.trkpts.last().time, | ||||
|                 commit=true, | ||||
|             ) | ||||
|             trackbook.database.commit() | ||||
|             handler.removeCallbacks(requery_and_render) | ||||
|             handler.postDelayed(requery_and_render, RERENDER_DELAY) | ||||
|         } | ||||
|  |  | |||
|  | @ -68,19 +68,22 @@ class Trackbook : Application() | |||
|     { | ||||
|         Log.i("VOUSSOIR", "Trackbook.load_database") | ||||
|         val folder = PreferencesHelper.load_database_folder() | ||||
|         this.database.commit() | ||||
|         if (this.database.ready) | ||||
|         { | ||||
|             Log.i("VOUSSOIR", "Trackbook.load_database: closing and re-opening.") | ||||
|             this.database.commit() | ||||
|             this.database.close() | ||||
|         } | ||||
|         if (folder == "") | ||||
|         { | ||||
|             Log.i("VOUSSOIR", "Trackbook.load_database: folder came up blank.") | ||||
|             this.database.ready = false | ||||
|             return | ||||
|         } | ||||
|         if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) | ||||
|         { | ||||
|             this.database.connect(File(folder + "/trkpt_${PreferencesHelper.load_device_id()}.db")) | ||||
|             val device_id = PreferencesHelper.load_device_id() | ||||
|             this.database.connect(File(folder + "/trkpt_${device_id}.db")) | ||||
|             this.load_homepoints() | ||||
|         } | ||||
|         else | ||||
|  |  | |||
|  | @ -56,7 +56,8 @@ class TrackerService: Service() | |||
|     var listeners_enabled_at: Long = 0 | ||||
|     var last_significant_motion: Long = 0 | ||||
|     var last_watchdog: Long = 0 | ||||
|     var gave_up_at: Long = 0 | ||||
|     var dead_at: Long = 0 | ||||
|     var dead_reason: String = "" | ||||
|     var arrived_at_home: Long = 0 | ||||
|     val TIME_UNTIL_SLEEP: Long = 5 * Keys.ONE_MINUTE_IN_MILLISECONDS | ||||
|     val TIME_UNTIL_DEAD: Long = 3 * Keys.ONE_MINUTE_IN_MILLISECONDS | ||||
|  | @ -185,7 +186,7 @@ class TrackerService: Service() | |||
|             Keys.STATE_FULL_RECORDING -> state_full_recording() | ||||
|             Keys.STATE_ARRIVED_AT_HOME -> state_arrived_at_home() | ||||
|             Keys.STATE_SLEEP -> state_sleep() | ||||
|             Keys.STATE_DEAD -> state_dead() | ||||
|             Keys.STATE_DEAD -> state_dead(dead_reason="Loaded previous state") | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | @ -200,7 +201,8 @@ class TrackerService: Service() | |||
|         trackbook.database.commit() | ||||
|         recent_displacement_locations.clear() | ||||
|         arrived_at_home = 0 | ||||
|         gave_up_at = 0 | ||||
|         dead_at = 0 | ||||
|         dead_reason = "" | ||||
|         if (foreground_started > 0) | ||||
|         { | ||||
|             stopForeground(STOP_FOREGROUND_DETACH) | ||||
|  | @ -215,11 +217,17 @@ class TrackerService: Service() | |||
|         // at full power. A wakelock is used to resist Android's doze. This state should be active | ||||
|         // while out and about. | ||||
|         Log.i("VOUSSOIR", "TrackerService.state_full_power") | ||||
|         if (! trackbook.database.ready) | ||||
|         { | ||||
|             state_dead("Database not ready") | ||||
|         } | ||||
|         trackbook.load_database() | ||||
|         tracking_state = Keys.STATE_FULL_RECORDING | ||||
|         PreferencesHelper.saveTrackingState(tracking_state) | ||||
|         reset_location_listeners(Keys.LOCATION_INTERVAL_FULL_POWER) | ||||
|         arrived_at_home = 0 | ||||
|         gave_up_at = 0 | ||||
|         dead_at = 0 | ||||
|         dead_reason = "" | ||||
|         if (foreground_started == 0L) | ||||
|         { | ||||
|             startForeground(Keys.TRACKER_SERVICE_NOTIFICATION_ID, displayNotification()) | ||||
|  | @ -231,7 +239,7 @@ class TrackerService: Service() | |||
|         } | ||||
|         else | ||||
|         { | ||||
|             state_dead() | ||||
|             state_dead("No listeners enabled") | ||||
|         } | ||||
|         displayNotification() | ||||
|     } | ||||
|  | @ -245,7 +253,8 @@ class TrackerService: Service() | |||
|         reset_location_listeners(Keys.LOCATION_INTERVAL_FULL_POWER) | ||||
|         trackbook.database.commit() | ||||
|         arrived_at_home = System.currentTimeMillis() | ||||
|         gave_up_at = 0 | ||||
|         dead_at = 0 | ||||
|         dead_reason = "" | ||||
|         stop_wakelock() | ||||
|         displayNotification() | ||||
|     } | ||||
|  | @ -258,11 +267,12 @@ class TrackerService: Service() | |||
|         PreferencesHelper.saveTrackingState(tracking_state) | ||||
|         reset_location_listeners(Keys.LOCATION_INTERVAL_SLEEP) | ||||
|         arrived_at_home = arrived_at_home | ||||
|         gave_up_at = 0 | ||||
|         dead_at = 0 | ||||
|         dead_reason = "" | ||||
|         stop_wakelock() | ||||
|         displayNotification() | ||||
|     } | ||||
|     fun state_dead() | ||||
|     fun state_dead(dead_reason: String) | ||||
|     { | ||||
|         // This state is activated when the device is struggling to receive a GPS fix due to being | ||||
|         // indoors / underground. It will be woken up again by the accelerometers or by plugging / | ||||
|  | @ -274,7 +284,8 @@ class TrackerService: Service() | |||
|         trackbook.database.commit() | ||||
|         recent_displacement_locations.clear() | ||||
|         arrived_at_home = 0 | ||||
|         gave_up_at = System.currentTimeMillis() | ||||
|         dead_at = System.currentTimeMillis() | ||||
|         this.dead_reason = dead_reason | ||||
|         stop_wakelock() | ||||
|         displayNotification() | ||||
|     } | ||||
|  | @ -287,12 +298,13 @@ class TrackerService: Service() | |||
|         PreferencesHelper.saveTrackingState(tracking_state) | ||||
|         reset_location_listeners(Keys.LOCATION_INTERVAL_FULL_POWER) | ||||
|         arrived_at_home = 0 | ||||
|         gave_up_at = 0 | ||||
|         dead_at = 0 | ||||
|         dead_reason = "" | ||||
|         stop_wakelock() | ||||
|         displayNotification() | ||||
|         if (!gpsLocationListenerRegistered && !networkLocationListenerRegistered) | ||||
|         { | ||||
|             state_dead() | ||||
|             state_dead(dead_reason="No listeners enabled") | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | @ -365,7 +377,8 @@ class TrackerService: Service() | |||
| 
 | ||||
|                 if(! trackbook.database.ready) | ||||
|                 { | ||||
|                     Log.i("VOUSSOIR", "Omitting due to database not ready.") | ||||
|                     Log.i("VOUSSOIR", "TrackerService.onLocationChanged: database is not ready!!.") | ||||
|                     state_dead(dead_reason="Database not ready") | ||||
|                     return | ||||
|                 } | ||||
| 
 | ||||
|  | @ -449,7 +462,7 @@ class TrackerService: Service() | |||
|                 } | ||||
| 
 | ||||
|                 val trkpt = Trkpt(device_id=device_id, location=location) | ||||
|                 trackbook.database.insert_trkpt(trkpt, commit=false) | ||||
|                 trackbook.database.insert_trkpt(trkpt) | ||||
| 
 | ||||
|                 if (trkpt.accuracy <= max_accuracy) | ||||
|                 { | ||||
|  | @ -503,26 +516,31 @@ class TrackerService: Service() | |||
|         if (tracking_state == Keys.STATE_FULL_RECORDING) | ||||
|         { | ||||
|             notification_builder.setContentTitle("${timestamp} (recording)") | ||||
|             notification_builder.setContentText(null) | ||||
|             notification_builder.setSmallIcon(R.drawable.ic_satellite_24dp) | ||||
|         } | ||||
|         else if (tracking_state == Keys.STATE_ARRIVED_AT_HOME) | ||||
|         { | ||||
|             notification_builder.setContentTitle("${timestamp} (home)") | ||||
|             notification_builder.setContentText(null) | ||||
|             notification_builder.setSmallIcon(R.drawable.ic_homepoint_24dp) | ||||
|         } | ||||
|         else if (tracking_state == Keys.STATE_SLEEP) | ||||
|         { | ||||
|             notification_builder.setContentTitle("${timestamp} (sleeping)") | ||||
|             notification_builder.setContentText(null) | ||||
|             notification_builder.setSmallIcon(R.drawable.ic_sleep_24dp) | ||||
|         } | ||||
|         else if (tracking_state == Keys.STATE_DEAD) | ||||
|         { | ||||
|             notification_builder.setContentTitle("${timestamp} (dead)") | ||||
|             notification_builder.setContentText(dead_reason) | ||||
|             notification_builder.setSmallIcon(R.drawable.ic_skull_24dp) | ||||
|         } | ||||
|         else if (tracking_state == Keys.STATE_STOP || tracking_state == Keys.STATE_MAPVIEW) | ||||
|         { | ||||
|             notification_builder.setContentTitle("${timestamp} (stopped)") | ||||
|             notification_builder.setContentText(null) | ||||
|             notification_builder.setSmallIcon(R.drawable.ic_fiber_manual_stop_24dp) | ||||
|         } | ||||
| 
 | ||||
|  | @ -832,7 +850,7 @@ class TrackerService: Service() | |||
|                 (now - last_significant_motion) > TIME_UNTIL_DEAD | ||||
|             ) | ||||
|             { | ||||
|                 state_dead() | ||||
|                 state_dead(dead_reason="No GPS reception") | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue