@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
)
|
||||
}
|
||||
|
||||
Referencia en una nueva incidencia
Block a user