Loading app/src/main/java/foundation/e/privacycentralapp/domain/usecases/FakeLocationStateUseCase.kt +39 −32 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ import foundation.e.privacymodules.permissions.data.ApplicationDescription import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import kotlin.random.Random Loading @@ -45,8 +46,12 @@ class FakeLocationStateUseCase( private val citiesRepository: CityDataSource, private val appDesc: ApplicationDescription, private val appContext: Context, private val coroutineScope: CoroutineScope coroutineScope: CoroutineScope ) { companion object { private const val TAG = "FakeLocationStateUseCase" } private val _configuredLocationMode = MutableStateFlow<Triple<LocationMode, Float?, Float?>>(Triple(LocationMode.REAL_LOCATION, null, null)) val configuredLocationMode: StateFlow<Triple<LocationMode, Float?, Float?>> = _configuredLocationMode Loading Loading @@ -131,67 +136,69 @@ class FakeLocationStateUseCase( val currentLocation = MutableStateFlow<Location?>(null) private var localListener = object : LocationListener { val providerName = LocationManager.NETWORK_PROVIDER override fun onLocationChanged(location: Location) { currentLocation.value = location currentLocation.update { previous -> if ((previous?.time ?: 0) + 1800 < location.time || (previous?.accuracy ?: Float.MAX_VALUE) > location.accuracy) { location } else { previous } } } // Deprecated since API 29, never called. override fun onStatusChanged(provider: String?, status: Int, extras: Bundle?) {} // TODO migration to minSdk31 , check still working. override fun onProviderEnabled(provider: String) { reset(provider) reset() } override fun onProviderDisabled(provider: String) { reset(provider) reset() } private fun reset(provider: String?) { if (provider == providerName) { private fun reset() { stopListeningLocation() currentLocation.value = null startListeningLocation() } } } fun startListeningLocation(): Boolean { return if (hasAcquireLocationPermission()) { requestLocationUpdates(localListener) requestLocationUpdates() true } else false } fun stopListeningLocation() { removeUpdates(localListener) locationManager.removeUpdates(localListener) } fun requestLocationUpdates(listener: LocationListener) { private fun requestLocationUpdates() { try { locationManager.requestLocationUpdates( LocationManager.NETWORK_PROVIDER, // TODO: tight this with fakelocation module. 0L, LocationManager.NETWORK_PROVIDER, 1000L, 0f, listener localListener ) // locationManager.requestLocationUpdates( // LocationManager.NETWORK_PROVIDER, // TODO: tight this with fakelocation module. // 0L, // 0f, // listener // ) val location: Location? = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER) location?.let { listener.onLocationChanged(it) } } catch (se: SecurityException) { Log.e("DebugLoc", "Missing permission", se) locationManager.requestLocationUpdates( LocationManager.GPS_PROVIDER, 1000L, 0f, localListener ) locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER)?: locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)?.let { localListener.onLocationChanged(it) } } catch (se: SecurityException) { Log.e(TAG, "Missing permission", se) } fun removeUpdates(listener: LocationListener) { locationManager.removeUpdates(listener) } } app/src/main/java/foundation/e/privacycentralapp/features/location/FakeLocationFragment.kt +12 −3 Original line number Diff line number Diff line Loading @@ -135,6 +135,15 @@ class FakeLocationFragment : NavToolbarFragment(R.layout.fragment_fake_location) bindClickListeners() render(viewModel.state.value) viewLifecycleOwner.lifecycleScope.launch { viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { viewModel.singleEvents.collect { event -> if (event is FakeLocationViewModel.SingleEvent.LocationUpdatedEvent) { updateLocation(event.location, event.mode) } } } } } } Loading @@ -156,9 +165,6 @@ class FakeLocationFragment : NavToolbarFragment(R.layout.fragment_fake_location) is FakeLocationViewModel.SingleEvent.ErrorEvent -> { displayToast(event.error) } is FakeLocationViewModel.SingleEvent.LocationUpdatedEvent -> { updateLocation(event.location, event.mode) } is FakeLocationViewModel.SingleEvent.RequestLocationPermission -> { // TODO for standalone: rationale dialog locationPermissionRequest.launch(arrayOf( Loading @@ -166,6 +172,9 @@ class FakeLocationFragment : NavToolbarFragment(R.layout.fragment_fake_location) Manifest.permission.ACCESS_COARSE_LOCATION )) } is FakeLocationViewModel.SingleEvent.LocationUpdatedEvent -> { // Nothing here, another collect linked to mapbox view. } } } } Loading Loading
app/src/main/java/foundation/e/privacycentralapp/domain/usecases/FakeLocationStateUseCase.kt +39 −32 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ import foundation.e.privacymodules.permissions.data.ApplicationDescription import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import kotlin.random.Random Loading @@ -45,8 +46,12 @@ class FakeLocationStateUseCase( private val citiesRepository: CityDataSource, private val appDesc: ApplicationDescription, private val appContext: Context, private val coroutineScope: CoroutineScope coroutineScope: CoroutineScope ) { companion object { private const val TAG = "FakeLocationStateUseCase" } private val _configuredLocationMode = MutableStateFlow<Triple<LocationMode, Float?, Float?>>(Triple(LocationMode.REAL_LOCATION, null, null)) val configuredLocationMode: StateFlow<Triple<LocationMode, Float?, Float?>> = _configuredLocationMode Loading Loading @@ -131,67 +136,69 @@ class FakeLocationStateUseCase( val currentLocation = MutableStateFlow<Location?>(null) private var localListener = object : LocationListener { val providerName = LocationManager.NETWORK_PROVIDER override fun onLocationChanged(location: Location) { currentLocation.value = location currentLocation.update { previous -> if ((previous?.time ?: 0) + 1800 < location.time || (previous?.accuracy ?: Float.MAX_VALUE) > location.accuracy) { location } else { previous } } } // Deprecated since API 29, never called. override fun onStatusChanged(provider: String?, status: Int, extras: Bundle?) {} // TODO migration to minSdk31 , check still working. override fun onProviderEnabled(provider: String) { reset(provider) reset() } override fun onProviderDisabled(provider: String) { reset(provider) reset() } private fun reset(provider: String?) { if (provider == providerName) { private fun reset() { stopListeningLocation() currentLocation.value = null startListeningLocation() } } } fun startListeningLocation(): Boolean { return if (hasAcquireLocationPermission()) { requestLocationUpdates(localListener) requestLocationUpdates() true } else false } fun stopListeningLocation() { removeUpdates(localListener) locationManager.removeUpdates(localListener) } fun requestLocationUpdates(listener: LocationListener) { private fun requestLocationUpdates() { try { locationManager.requestLocationUpdates( LocationManager.NETWORK_PROVIDER, // TODO: tight this with fakelocation module. 0L, LocationManager.NETWORK_PROVIDER, 1000L, 0f, listener localListener ) // locationManager.requestLocationUpdates( // LocationManager.NETWORK_PROVIDER, // TODO: tight this with fakelocation module. // 0L, // 0f, // listener // ) val location: Location? = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER) location?.let { listener.onLocationChanged(it) } } catch (se: SecurityException) { Log.e("DebugLoc", "Missing permission", se) locationManager.requestLocationUpdates( LocationManager.GPS_PROVIDER, 1000L, 0f, localListener ) locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER)?: locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)?.let { localListener.onLocationChanged(it) } } catch (se: SecurityException) { Log.e(TAG, "Missing permission", se) } fun removeUpdates(listener: LocationListener) { locationManager.removeUpdates(listener) } }
app/src/main/java/foundation/e/privacycentralapp/features/location/FakeLocationFragment.kt +12 −3 Original line number Diff line number Diff line Loading @@ -135,6 +135,15 @@ class FakeLocationFragment : NavToolbarFragment(R.layout.fragment_fake_location) bindClickListeners() render(viewModel.state.value) viewLifecycleOwner.lifecycleScope.launch { viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { viewModel.singleEvents.collect { event -> if (event is FakeLocationViewModel.SingleEvent.LocationUpdatedEvent) { updateLocation(event.location, event.mode) } } } } } } Loading @@ -156,9 +165,6 @@ class FakeLocationFragment : NavToolbarFragment(R.layout.fragment_fake_location) is FakeLocationViewModel.SingleEvent.ErrorEvent -> { displayToast(event.error) } is FakeLocationViewModel.SingleEvent.LocationUpdatedEvent -> { updateLocation(event.location, event.mode) } is FakeLocationViewModel.SingleEvent.RequestLocationPermission -> { // TODO for standalone: rationale dialog locationPermissionRequest.launch(arrayOf( Loading @@ -166,6 +172,9 @@ class FakeLocationFragment : NavToolbarFragment(R.layout.fragment_fake_location) Manifest.permission.ACCESS_COARSE_LOCATION )) } is FakeLocationViewModel.SingleEvent.LocationUpdatedEvent -> { // Nothing here, another collect linked to mapbox view. } } } } Loading