mirror of
https://github.com/permissionlesstech/bitchat-android.git
synced 2026-07-24 22:25:19 +00:00
Refactor: Add timeout and tracking to SystemLocationProvider
Implements robust cleanup and timeout logic for location requests. - SystemLocationProvider: Adds 30s timeout and listener tracking for legacy one-shot requests to prevent memory leaks on pre-Android 11 devices. - FusedLocationProvider: Adds 30s duration to requests. - LocationProvider: Adds cancel() method for full resource cleanup. - LocationChannelManager: Ensures cancel() is called during cleanup.
This commit is contained in:
@@ -58,6 +58,7 @@ class FusedLocationProvider(private val context: Context) : LocationProvider {
|
||||
try {
|
||||
val request = CurrentLocationRequest.Builder()
|
||||
.setPriority(Priority.PRIORITY_HIGH_ACCURACY)
|
||||
.setDurationMillis(30000)
|
||||
.build()
|
||||
|
||||
fusedLocationClient.getCurrentLocation(request, null)
|
||||
@@ -124,4 +125,18 @@ class FusedLocationProvider(private val context: Context) : LocationProvider {
|
||||
Log.e(TAG, "Error removing fused updates: ${e.message}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun cancel() {
|
||||
try {
|
||||
synchronized(activeCallbacks) {
|
||||
for ((callback, locationCallback) in activeCallbacks) {
|
||||
fusedLocationClient.removeLocationUpdates(locationCallback)
|
||||
}
|
||||
activeCallbacks.clear()
|
||||
}
|
||||
Log.d(TAG, "Cancelled all fused updates")
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Error cancelling fused provider: ${e.message}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -576,6 +576,7 @@ class LocationChannelManager private constructor(private val context: Context) {
|
||||
fun cleanup() {
|
||||
Log.d(TAG, "Cleaning up LocationChannelManager")
|
||||
endLiveRefresh()
|
||||
locationProvider.cancel()
|
||||
|
||||
geocodingJob?.cancel()
|
||||
geocodingJob = null
|
||||
|
||||
@@ -32,4 +32,9 @@ interface LocationProvider {
|
||||
* @param callback The same callback instance passed to requestLocationUpdates.
|
||||
*/
|
||||
fun removeLocationUpdates(callback: (Location) -> Unit)
|
||||
|
||||
/**
|
||||
* Cancel any pending one-shot location requests and cleanup resources.
|
||||
*/
|
||||
fun cancel()
|
||||
}
|
||||
|
||||
@@ -19,8 +19,12 @@ class SystemLocationProvider(private val context: Context) : LocationProvider {
|
||||
}
|
||||
|
||||
private val locationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
|
||||
private val handler = android.os.Handler(android.os.Looper.getMainLooper())
|
||||
|
||||
// Map to keep track of listeners to unregister them later
|
||||
private val activeListeners = mutableMapOf<(Location) -> Unit, LocationListener>()
|
||||
private val activeOneShotListeners = mutableMapOf<(Location?) -> Unit, LocationListener>()
|
||||
private val activeOneShotRunnables = mutableMapOf<(Location?) -> Unit, Runnable>()
|
||||
|
||||
private fun hasLocationPermission(): Boolean {
|
||||
return ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED ||
|
||||
@@ -80,17 +84,47 @@ class SystemLocationProvider(private val context: Context) : LocationProvider {
|
||||
callback(location)
|
||||
}
|
||||
} else {
|
||||
// For older versions, use requestSingleUpdate
|
||||
// For older versions, use requestSingleUpdate with timeout mechanism
|
||||
val timeoutRunnable = Runnable {
|
||||
Log.w(TAG, "Location request timed out")
|
||||
synchronized(activeOneShotListeners) {
|
||||
val listener = activeOneShotListeners.remove(callback)
|
||||
activeOneShotRunnables.remove(callback)
|
||||
if (listener != null) {
|
||||
try {
|
||||
locationManager.removeUpdates(listener)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Error removing timed out listener: ${e.message}")
|
||||
}
|
||||
}
|
||||
}
|
||||
callback(null)
|
||||
}
|
||||
|
||||
val listener = object : LocationListener {
|
||||
override fun onLocationChanged(location: Location) {
|
||||
callback(location)
|
||||
synchronized(activeOneShotListeners) {
|
||||
activeOneShotListeners.remove(callback)
|
||||
val runnable = activeOneShotRunnables.remove(callback)
|
||||
if (runnable != null) {
|
||||
handler.removeCallbacks(runnable)
|
||||
}
|
||||
}
|
||||
locationManager.removeUpdates(this)
|
||||
callback(location)
|
||||
}
|
||||
override fun onStatusChanged(provider: String?, status: Int, extras: Bundle?) {}
|
||||
override fun onProviderEnabled(provider: String) {}
|
||||
override fun onProviderDisabled(provider: String) {}
|
||||
}
|
||||
|
||||
synchronized(activeOneShotListeners) {
|
||||
activeOneShotListeners[callback] = listener
|
||||
activeOneShotRunnables[callback] = timeoutRunnable
|
||||
}
|
||||
|
||||
locationManager.requestSingleUpdate(provider, listener, null)
|
||||
handler.postDelayed(timeoutRunnable, 30000L) // 30s timeout
|
||||
}
|
||||
providerFound = true
|
||||
break
|
||||
@@ -169,4 +203,32 @@ class SystemLocationProvider(private val context: Context) : LocationProvider {
|
||||
Log.e(TAG, "Error removing updates: ${e.message}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun cancel() {
|
||||
try {
|
||||
// Cancel continuous updates
|
||||
synchronized(activeListeners) {
|
||||
for ((_, listener) in activeListeners) {
|
||||
try { locationManager.removeUpdates(listener) } catch (_: Exception) {}
|
||||
}
|
||||
activeListeners.clear()
|
||||
}
|
||||
|
||||
// Cancel one-shot requests
|
||||
synchronized(activeOneShotListeners) {
|
||||
for ((_, listener) in activeOneShotListeners) {
|
||||
try { locationManager.removeUpdates(listener) } catch (_: Exception) {}
|
||||
}
|
||||
activeOneShotListeners.clear()
|
||||
|
||||
for ((_, runnable) in activeOneShotRunnables) {
|
||||
handler.removeCallbacks(runnable)
|
||||
}
|
||||
activeOneShotRunnables.clear()
|
||||
}
|
||||
Log.d(TAG, "Cancelled all system location requests")
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Error cancelling system provider: ${e.message}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user