update LocationManager

Signed-off-by: ale <ale@manalejandro.com>
Este commit está contenido en:
ale
2025-07-20 22:12:27 +02:00
padre 09a9758850
commit f0059d3719
Se han modificado 3 ficheros con 342 adiciones y 181 borrados

Ver fichero

@@ -17,6 +17,8 @@ class LocationService(private val context: Context) {
)
}
private val locationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
/**
* Simula obtener la última ubicación conocida que Google tendría guardada
* Devuelve una ubicación predeterminada o la última simulada
@@ -65,20 +67,8 @@ class LocationService(private val context: Context) {
* Guarda una ubicación simulada en todos los proveedores
*/
suspend fun mockLocation(latitude: Double, longitude: Double): Boolean {
return try {
val timestamp = System.currentTimeMillis()
// Guardar la ubicación en todos los proveedores
ALL_PROVIDERS.forEach { provider ->
saveLocationForProvider(provider, latitude, longitude, timestamp)
}
// Simular un pequeño delay
delay(500)
true
} catch (e: Exception) {
false
}
// Usar el nuevo método que incluye LocationManager
return setMockLocationOnAllProviders(latitude, longitude)
}
/**
@@ -256,7 +246,7 @@ class LocationService(private val context: Context) {
val coordinates = popularLocations[cityName]
return if (coordinates != null) {
mockLocation(coordinates.first, coordinates.second)
setMockLocationOnAllProviders(coordinates.first, coordinates.second)
} else {
false
}
@@ -287,4 +277,144 @@ class LocationService(private val context: Context) {
null
}
}
/**
* Establece una ubicación simulada usando LocationManager en todos los proveedores del sistema
*/
suspend fun setMockLocationOnAllProviders(latitude: Double, longitude: Double): Boolean {
return try {
val timestamp = System.currentTimeMillis()
// Guardar la ubicación en SharedPreferences para todos los proveedores
ALL_PROVIDERS.forEach { provider ->
saveLocationForProvider(provider, latitude, longitude, timestamp)
}
// Establecer la ubicación simulada usando LocationManager para cada proveedor disponible
ALL_PROVIDERS.forEach { provider ->
try {
if (isProviderAvailable(provider)) {
setMockLocationForProvider(provider, latitude, longitude, timestamp)
}
} catch (e: Exception) {
// Continuar con otros proveedores si uno falla
android.util.Log.w("LocationService", "Error setting mock location for $provider: ${e.message}")
}
}
delay(500)
true
} catch (e: Exception) {
android.util.Log.e("LocationService", "Error setting mock location on all providers", e)
false
}
}
/**
* Establece una ubicación simulada para un proveedor específico usando LocationManager
*/
private fun setMockLocationForProvider(provider: String, latitude: Double, longitude: Double, timestamp: Long) {
if (provider == "fused") {
// El proveedor fused no es directamente accesible vía LocationManager
return
}
try {
val location = Location(provider).apply {
this.latitude = latitude
this.longitude = longitude
time = timestamp
accuracy = when (provider) {
LocationManager.GPS_PROVIDER -> 5.0f
LocationManager.NETWORK_PROVIDER -> 20.0f
LocationManager.PASSIVE_PROVIDER -> 15.0f
else -> 10.0f
}
// Establecer campos adicionales para hacer la ubicación más realista
bearing = 0.0f
speed = 0.0f
altitude = 650.0 // Altura aproximada de Madrid
}
// Habilitar ubicaciones simuladas para el proveedor
if (locationManager.isProviderEnabled(provider)) {
locationManager.setTestProviderEnabled(provider, true)
locationManager.setTestProviderLocation(provider, location)
}
} catch (e: SecurityException) {
android.util.Log.w("LocationService", "Permission denied for mock location on $provider")
} catch (e: IllegalArgumentException) {
android.util.Log.w("LocationService", "Provider $provider not available for mock location")
} catch (e: Exception) {
android.util.Log.e("LocationService", "Error setting test provider location for $provider", e)
}
}
/**
* Verifica si un proveedor está disponible
*/
private fun isProviderAvailable(provider: String): Boolean {
if (provider == "fused") return true // Siempre consideramos fused como disponible
return try {
locationManager.isProviderEnabled(provider) ||
locationManager.allProviders.contains(provider)
} catch (e: Exception) {
false
}
}
/**
* Configura los proveedores de prueba necesarios
*/
fun setupTestProviders() {
ALL_PROVIDERS.forEach { provider ->
if (provider == "fused") return@forEach // Skip fused provider
try {
// Eliminar proveedor de prueba existente si existe
try {
locationManager.removeTestProvider(provider)
} catch (e: Exception) {
// Ignorar si no existe
}
// Agregar proveedor de prueba
locationManager.addTestProvider(
provider,
false, // requiresNetwork
false, // requiresSatellite
false, // requiresCell
false, // hasMonetaryCost
true, // supportsAltitude
true, // supportsSpeed
true, // supportsBearing
android.location.Criteria.POWER_MEDIUM, // powerRequirement
android.location.Criteria.ACCURACY_FINE // accuracy
)
locationManager.setTestProviderEnabled(provider, true)
} catch (e: SecurityException) {
android.util.Log.w("LocationService", "Permission denied for test provider $provider")
} catch (e: Exception) {
android.util.Log.e("LocationService", "Error setting up test provider $provider", e)
}
}
}
/**
* Limpia los proveedores de prueba
*/
fun cleanupTestProviders() {
ALL_PROVIDERS.forEach { provider ->
if (provider == "fused") return@forEach // Skip fused provider
try {
locationManager.setTestProviderEnabled(provider, false)
locationManager.removeTestProvider(provider)
} catch (e: Exception) {
// Ignorar errores al limpiar
}
}
}
}

Ver fichero

@@ -88,9 +88,9 @@ fun LocationApp() {
)
// Mostrar errores
uiState.error?.let { error ->
uiState.error?.let { errorMessage ->
ErrorSection(
error = error,
error = errorMessage,
onDismiss = viewModel::clearError
)
}
@@ -219,6 +219,7 @@ fun CustomLocationSection(
) {
var latitude by remember { mutableStateOf("") }
var longitude by remember { mutableStateOf("") }
var pendingLocation by remember { mutableStateOf<Pair<Double, Double>?>(null) }
Card(modifier = Modifier.fillMaxWidth()) {
Column(
@@ -237,7 +238,10 @@ fun CustomLocationSection(
) {
OutlinedTextField(
value = latitude,
onValueChange = { latitude = it },
onValueChange = {
latitude = it
pendingLocation = null // Limpiar ubicación pendiente al editar
},
label = { Text("Latitud") },
placeholder = { Text("40.4168") },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Decimal),
@@ -246,7 +250,10 @@ fun CustomLocationSection(
OutlinedTextField(
value = longitude,
onValueChange = { longitude = it },
onValueChange = {
longitude = it
pendingLocation = null // Limpiar ubicación pendiente al editar
},
label = { Text("Longitud") },
placeholder = { Text("-3.7038") },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Decimal),
@@ -254,23 +261,74 @@ fun CustomLocationSection(
)
}
Button(
onClick = {
val lat = latitude.toDoubleOrNull()
val lng = longitude.toDoubleOrNull()
if (lat != null && lng != null) {
onMockLocation(lat, lng)
// Mostrar ubicación pendiente si existe
pendingLocation?.let { (lat, lng) ->
Card(
modifier = Modifier.fillMaxWidth(),
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.tertiaryContainer)
) {
Column(
modifier = Modifier.padding(12.dp),
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
Text(
text = "Ubicación Lista para Establecer",
fontWeight = FontWeight.Medium,
color = MaterialTheme.colorScheme.onTertiaryContainer
)
Text(
text = "Lat: ${String.format("%.6f", lat)}, Lng: ${String.format("%.6f", lng)}",
color = MaterialTheme.colorScheme.onTertiaryContainer
)
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
Button(
onClick = {
onMockLocation(lat, lng)
pendingLocation = null
latitude = ""
longitude = ""
},
enabled = !uiState.isLoading,
modifier = Modifier.weight(1f)
) {
Text("✓ Aceptar y Establecer")
}
OutlinedButton(
onClick = { pendingLocation = null },
modifier = Modifier.weight(1f)
) {
Text("✗ Cancelar")
}
}
}
},
enabled = latitude.isNotBlank() && longitude.isNotBlank() && !uiState.isLoading,
modifier = Modifier.fillMaxWidth()
) {
Text("Establecer Ubicación Personalizada")
}
}
// Botón para preparar la ubicación
if (pendingLocation == null) {
Button(
onClick = {
val lat = latitude.toDoubleOrNull()
val lng = longitude.toDoubleOrNull()
if (lat != null && lng != null && lat >= -90 && lat <= 90 && lng >= -180 && lng <= 180) {
pendingLocation = Pair(lat, lng)
}
},
enabled = latitude.isNotBlank() && longitude.isNotBlank() && !uiState.isLoading,
modifier = Modifier.fillMaxWidth()
) {
Text("Preparar Ubicación Personalizada")
}
}
uiState.mockedLocation?.let { location ->
LocationDisplay(
title = "Ubicación Guardada",
title = "Ubicación Establecida en Todos los Proveedores",
location = location
)
}