163 lines
5.3 KiB
Kotlin
163 lines
5.3 KiB
Kotlin
package org.pupes.mhdrunpathfinder
|
|
|
|
import android.Manifest
|
|
import android.app.Activity
|
|
import android.content.Context
|
|
import android.content.pm.PackageManager
|
|
import android.location.Location
|
|
import android.location.LocationListener
|
|
import android.location.LocationManager
|
|
import android.os.Handler
|
|
import android.os.Looper
|
|
import android.widget.Toast
|
|
import androidx.core.app.ActivityCompat
|
|
import ovh.plrapps.mapcompose.api.moveMarker
|
|
|
|
// Handler for main thread operations
|
|
private val LocationMainHandler = Handler(Looper.getMainLooper())
|
|
private var locationManager: LocationManager? = null
|
|
private var locationListener: LocationListener? = null
|
|
private var isLocationTracking = false
|
|
|
|
// Location update configuration
|
|
private const val MIN_TIME_BETWEEN_UPDATES = 1000L // 1 second in milliseconds
|
|
private const val MIN_DISTANCE_CHANGE = 0f // 0 meters - update on any movement
|
|
|
|
// LocationListener callback
|
|
private val createLocationListener: (Activity) -> LocationListener = { callee ->
|
|
LocationListener { location ->
|
|
handleLocationUpdate(location, callee)
|
|
}
|
|
}
|
|
|
|
private fun handleLocationUpdate(location: Location, callee: Activity) {
|
|
try {
|
|
val normalizedX = longitudeToXNormalized(location.longitude)
|
|
val normalizedY = latitudeToYNormalized(location.latitude)
|
|
|
|
// Update marker on main thread
|
|
LocationMainHandler.post {
|
|
try {
|
|
mapState.moveMarker(
|
|
"current_position",
|
|
x = normalizedX,
|
|
y = normalizedY
|
|
)
|
|
} catch (e: Exception) {
|
|
// Marker might not exist yet, silently ignore
|
|
}
|
|
}
|
|
} catch (e: Exception) {
|
|
LocationMainHandler.post {
|
|
Toast.makeText(callee, "Location error: ${e.message}", Toast.LENGTH_SHORT).show()
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check if location permissions are granted
|
|
private fun hasLocationPermissions(context: Context): Boolean {
|
|
return ActivityCompat.checkSelfPermission(
|
|
context,
|
|
Manifest.permission.ACCESS_FINE_LOCATION
|
|
) == PackageManager.PERMISSION_GRANTED ||
|
|
ActivityCompat.checkSelfPermission(
|
|
context,
|
|
Manifest.permission.ACCESS_COARSE_LOCATION
|
|
) == PackageManager.PERMISSION_GRANTED
|
|
}
|
|
|
|
// Start continuous location tracking
|
|
fun startLocationTracking(callee: Activity) {
|
|
if (isLocationTracking) {
|
|
Toast.makeText(callee, "Location tracking already active", Toast.LENGTH_SHORT).show()
|
|
return
|
|
}
|
|
|
|
if (!hasLocationPermissions(callee)) {
|
|
Toast.makeText(callee, "Location permissions not granted", Toast.LENGTH_LONG).show()
|
|
// Request permissions
|
|
ActivityCompat.requestPermissions(
|
|
callee,
|
|
arrayOf(
|
|
Manifest.permission.ACCESS_FINE_LOCATION,
|
|
Manifest.permission.ACCESS_COARSE_LOCATION
|
|
),
|
|
LOCATION_PERMISSION_REQUEST_CODE
|
|
)
|
|
return
|
|
}
|
|
|
|
try {
|
|
locationManager = callee.getSystemService(Context.LOCATION_SERVICE) as LocationManager
|
|
locationListener = createLocationListener(callee)
|
|
|
|
// Try GPS first, then network provider
|
|
val providers = listOf(
|
|
LocationManager.GPS_PROVIDER,
|
|
LocationManager.NETWORK_PROVIDER
|
|
)
|
|
|
|
var providerFound = false
|
|
for (provider in providers) {
|
|
if (locationManager?.isProviderEnabled(provider) == true) {
|
|
try {
|
|
locationManager?.requestLocationUpdates(
|
|
provider,
|
|
MIN_TIME_BETWEEN_UPDATES,
|
|
MIN_DISTANCE_CHANGE,
|
|
locationListener!!,
|
|
Looper.getMainLooper()
|
|
)
|
|
providerFound = true
|
|
|
|
// Get last known location and update immediately
|
|
locationManager?.getLastKnownLocation(provider)?.let { location ->
|
|
handleLocationUpdate(location, callee)
|
|
}
|
|
|
|
break
|
|
} catch (e: SecurityException) {
|
|
// Permission denied
|
|
Toast.makeText(callee, "Location permission denied", Toast.LENGTH_LONG).show()
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!providerFound) {
|
|
Toast.makeText(callee, "No location provider available. Please enable GPS or network location", Toast.LENGTH_LONG).show()
|
|
return
|
|
}
|
|
|
|
isLocationTracking = true
|
|
Toast.makeText(callee, "Location tracking started", Toast.LENGTH_SHORT).show()
|
|
|
|
} catch (e: Exception) {
|
|
Toast.makeText(callee, "Failed to start location tracking: ${e.message}", Toast.LENGTH_LONG).show()
|
|
}
|
|
}
|
|
|
|
// Stop location tracking
|
|
fun stopLocationTracking() {
|
|
if (!isLocationTracking) return
|
|
|
|
try {
|
|
locationListener?.let { listener ->
|
|
locationManager?.removeUpdates(listener)
|
|
}
|
|
locationListener = null
|
|
locationManager = null
|
|
isLocationTracking = false
|
|
} catch (e: Exception) {
|
|
// Silently handle cleanup errors
|
|
}
|
|
}
|
|
|
|
// Get current tracking status
|
|
fun isLocationTrackingActive(): Boolean {
|
|
return isLocationTracking
|
|
}
|
|
|
|
// Permission request code
|
|
const val LOCATION_PERMISSION_REQUEST_CODE = 1001
|