feat: implement two-location speed calculation when native speed unavailable
This commit is contained in:
parent
eca39e542c
commit
c9e49c6cbd
1 changed files with 88 additions and 6 deletions
|
|
@ -13,7 +13,9 @@ import android.net.ConnectivityManager
|
||||||
import android.location.Location
|
import android.location.Location
|
||||||
import android.os.Binder
|
import android.os.Binder
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
|
import android.os.Handler
|
||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
|
import android.os.Looper
|
||||||
import android.os.PowerManager
|
import android.os.PowerManager
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import dev.fiatcode.tracpulse.BridgeModule
|
import dev.fiatcode.tracpulse.BridgeModule
|
||||||
|
|
@ -57,6 +59,9 @@ class LocationTrackingService : Service() {
|
||||||
private var bypassFilterOnce = false
|
private var bypassFilterOnce = false
|
||||||
|
|
||||||
private var currentConfig: TrackingConfig? = null
|
private var currentConfig: TrackingConfig? = null
|
||||||
|
private var pendingSpeedLocation: Location? = null
|
||||||
|
private var speedRequestPending = false
|
||||||
|
private val SPEED_CALC_DELAY_MS = 2500L
|
||||||
|
|
||||||
inner class LocalBinder : Binder() {
|
inner class LocalBinder : Binder() {
|
||||||
fun getService(): LocationTrackingService = this@LocationTrackingService
|
fun getService(): LocationTrackingService = this@LocationTrackingService
|
||||||
|
|
@ -143,6 +148,8 @@ class LocationTrackingService : Service() {
|
||||||
|
|
||||||
isTracking = true
|
isTracking = true
|
||||||
distanceFilterProcessor.reset()
|
distanceFilterProcessor.reset()
|
||||||
|
pendingSpeedLocation = null
|
||||||
|
speedRequestPending = false
|
||||||
prefs.edit().putBoolean("tracking_active", true).apply()
|
prefs.edit().putBoolean("tracking_active", true).apply()
|
||||||
Log.d(TAG, "startTracking: set tracking_active=true")
|
Log.d(TAG, "startTracking: set tracking_active=true")
|
||||||
|
|
||||||
|
|
@ -226,15 +233,22 @@ class LocationTrackingService : Service() {
|
||||||
}
|
}
|
||||||
bypassFilterOnce = false
|
bypassFilterOnce = false
|
||||||
|
|
||||||
|
val nativeSpeed = if (location.hasSpeed()) location.speed else null
|
||||||
|
|
||||||
|
if (nativeSpeed == null || nativeSpeed <= 0) {
|
||||||
|
pendingSpeedLocation = location
|
||||||
|
requestLocationForSpeedCalculation()
|
||||||
|
}
|
||||||
|
|
||||||
val traccarLocation = TraccarLocation(
|
val traccarLocation = TraccarLocation(
|
||||||
timestamp = location.time,
|
timestamp = location.time,
|
||||||
latitude = location.latitude,
|
latitude = location.latitude,
|
||||||
longitude = location.longitude,
|
longitude = location.longitude,
|
||||||
accuracy = if (location.hasAccuracy()) location.accuracy else null,
|
accuracy = if (location.hasAccuracy()) location.accuracy else null,
|
||||||
speed = if (location.hasSpeed()) location.speed else null,
|
speed = nativeSpeed,
|
||||||
heading = if (location.hasBearing()) location.bearing else null,
|
heading = if (location.hasBearing()) location.bearing else null,
|
||||||
altitude = if (location.hasAltitude()) location.altitude else null,
|
altitude = if (location.hasAltitude()) location.altitude else null,
|
||||||
isMoving = location.speed > 1.0f // Consider moving if speed > 1 m/s
|
isMoving = (nativeSpeed ?: 0f) > 1.0f
|
||||||
)
|
)
|
||||||
|
|
||||||
logEvent("LOCATION", "Lat: ${location.latitude}, Lon: ${location.longitude}, Speed: ${location.speed}")
|
logEvent("LOCATION", "Lat: ${location.latitude}, Lon: ${location.longitude}, Speed: ${location.speed}")
|
||||||
|
|
@ -262,12 +276,14 @@ class LocationTrackingService : Service() {
|
||||||
apply()
|
apply()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (nativeSpeed != null && nativeSpeed > 0) {
|
||||||
if (isNetworkAvailable) {
|
if (isNetworkAvailable) {
|
||||||
sendLocationToServer(traccarLocation)
|
sendLocationToServer(traccarLocation)
|
||||||
} else {
|
} else {
|
||||||
bufferLocation(traccarLocation)
|
bufferLocation(traccarLocation)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun onHeartbeat() {
|
private fun onHeartbeat() {
|
||||||
logEvent("HEARTBEAT", "Heartbeat fired")
|
logEvent("HEARTBEAT", "Heartbeat fired")
|
||||||
|
|
@ -276,6 +292,58 @@ class LocationTrackingService : Service() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun requestLocationForSpeedCalculation() {
|
||||||
|
if (speedRequestPending) return
|
||||||
|
|
||||||
|
speedRequestPending = true
|
||||||
|
Handler(Looper.getMainLooper()).postDelayed({
|
||||||
|
fusedLocationProvider.getLastLocation { location ->
|
||||||
|
location?.let {
|
||||||
|
val calculatedSpeed = distanceFilterProcessor.getCalculatedSpeed(it)
|
||||||
|
onSpeedLocationReceived(it, calculatedSpeed)
|
||||||
|
}
|
||||||
|
speedRequestPending = false
|
||||||
|
pendingSpeedLocation = null
|
||||||
|
}
|
||||||
|
}, SPEED_CALC_DELAY_MS)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onSpeedLocationReceived(location: Location, calculatedSpeed: Float?) {
|
||||||
|
val config = currentConfig ?: return
|
||||||
|
|
||||||
|
val finalSpeed = if (location.hasSpeed() && location.speed > 0) {
|
||||||
|
location.speed
|
||||||
|
} else {
|
||||||
|
calculatedSpeed
|
||||||
|
}
|
||||||
|
|
||||||
|
if (finalSpeed == null || finalSpeed <= 0) {
|
||||||
|
logEvent("SPEED_CALC", "Speed calculation failed - insufficient data")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val traccarLocation = TraccarLocation(
|
||||||
|
timestamp = location.time,
|
||||||
|
latitude = location.latitude,
|
||||||
|
longitude = location.longitude,
|
||||||
|
accuracy = if (location.hasAccuracy()) location.accuracy else null,
|
||||||
|
speed = finalSpeed,
|
||||||
|
heading = if (location.hasBearing()) location.bearing else null,
|
||||||
|
altitude = if (location.hasAltitude()) location.altitude else null,
|
||||||
|
isMoving = finalSpeed > 1.0f
|
||||||
|
)
|
||||||
|
|
||||||
|
logEvent("LOCATION", "Lat: ${location.latitude}, Lon: ${location.longitude}, Calc Speed: ${finalSpeed}")
|
||||||
|
|
||||||
|
updateNotificationSpeed(location, finalSpeed)
|
||||||
|
|
||||||
|
if (isNetworkAvailable) {
|
||||||
|
sendLocationToServer(traccarLocation)
|
||||||
|
} else {
|
||||||
|
bufferLocation(traccarLocation)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun sendLocationToServer(location: TraccarLocation) {
|
private fun sendLocationToServer(location: TraccarLocation) {
|
||||||
val config = currentConfig ?: return
|
val config = currentConfig ?: return
|
||||||
val traccarConfig = TraccarConfig(
|
val traccarConfig = TraccarConfig(
|
||||||
|
|
@ -407,6 +475,20 @@ class LocationTrackingService : Service() {
|
||||||
notificationManager.notify(NOTIFICATION_ID, notification)
|
notificationManager.notify(NOTIFICATION_ID, notification)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun updateNotificationSpeed(location: Location, speed: Float) {
|
||||||
|
val content = buildString {
|
||||||
|
append("Lat: %.4f Lon: %.4f".format(location.latitude, location.longitude))
|
||||||
|
append("\nSpeed: %.0f km/h (calc)".format(speed * 3.6))
|
||||||
|
val time = java.text.SimpleDateFormat("HH:mm:ss", java.util.Locale.getDefault())
|
||||||
|
.format(java.util.Date(location.time))
|
||||||
|
append("\nLast: $time")
|
||||||
|
}
|
||||||
|
|
||||||
|
val notification = createNotification(content)
|
||||||
|
val notificationManager = getSystemService(NotificationManager::class.java)
|
||||||
|
notificationManager.notify(NOTIFICATION_ID, notification)
|
||||||
|
}
|
||||||
|
|
||||||
private fun acquireWakeLock() {
|
private fun acquireWakeLock() {
|
||||||
val powerManager = getSystemService(Context.POWER_SERVICE) as PowerManager
|
val powerManager = getSystemService(Context.POWER_SERVICE) as PowerManager
|
||||||
wakeLock = powerManager.newWakeLock(
|
wakeLock = powerManager.newWakeLock(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue