Loading app/src/main/java/foundation/e/privacycentralapp/domain/usecases/FakeLocationStateUseCase.kt +14 −15 Original line number Original line Diff line number Diff line Loading @@ -61,23 +61,15 @@ class FakeLocationStateUseCase( private val locationManager: LocationManager private val locationManager: LocationManager get() = appContext.getSystemService(Context.LOCATION_SERVICE) as LocationManager get() = appContext.getSystemService(Context.LOCATION_SERVICE) as LocationManager private fun acquireLocationPermission() { private fun acquireLocationPermission(): Boolean { if (appContext.checkSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { return (appContext.checkSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) permissionsModule.toggleDangerousPermission( || false // TODO : should return true / false. permissionsModule.toggleDangerousPermission(appDesc, android.Manifest.permission.ACCESS_FINE_LOCATION, true) appDesc, android.Manifest.permission.ACCESS_FINE_LOCATION, true ) } } } private fun applySettings(isQuickPrivacyEnabled: Boolean, fakeLocation: Pair<Float, Float>?, isSpecificLocation: Boolean = false) { private fun applySettings(isQuickPrivacyEnabled: Boolean, fakeLocation: Pair<Float, Float>?, isSpecificLocation: Boolean = false) { _configuredLocationMode.value = computeLocationMode(fakeLocation, isSpecificLocation) _configuredLocationMode.value = computeLocationMode(fakeLocation, isSpecificLocation) if (isQuickPrivacyEnabled && fakeLocation != null) { if (isQuickPrivacyEnabled && fakeLocation != null && acquireMockLocationPermission()) { if (permissionsModule.getAppOpMode(appDesc, AppOpsManager.OPSTR_MOCK_LOCATION) != AppOpModes.ALLOWED) { permissionsModule.setAppOpMode(appDesc, AppOpsManager.OPSTR_MOCK_LOCATION, AppOpModes.ALLOWED) } fakeLocationModule.startFakeLocation() fakeLocationModule.startFakeLocation() fakeLocationModule.setFakeLocation(fakeLocation.first.toDouble(), fakeLocation.second.toDouble()) fakeLocationModule.setFakeLocation(fakeLocation.first.toDouble(), fakeLocation.second.toDouble()) localStateRepository.locationMode.value = configuredLocationMode.value.first localStateRepository.locationMode.value = configuredLocationMode.value.first Loading @@ -87,6 +79,11 @@ class FakeLocationStateUseCase( } } } } private fun acquireMockLocationPermission(): Boolean { return (permissionsModule.getAppOpMode(appDesc, AppOpsManager.OPSTR_MOCK_LOCATION) == AppOpModes.ALLOWED) || permissionsModule.setAppOpMode(appDesc, AppOpsManager.OPSTR_MOCK_LOCATION, AppOpModes.ALLOWED) == null } fun setSpecificLocation(latitude: Float, longitude: Float) { fun setSpecificLocation(latitude: Float, longitude: Float) { if (!localStateRepository.isQuickPrivacyEnabled) { if (!localStateRepository.isQuickPrivacyEnabled) { localStateRepository.setShowQuickPrivacyDisabledMessage(true) localStateRepository.setShowQuickPrivacyDisabledMessage(true) Loading Loading @@ -161,8 +158,11 @@ class FakeLocationStateUseCase( } } } } fun startListeningLocation() { fun startListeningLocation(): Boolean { return if (acquireLocationPermission()) { requestLocationUpdates(localListener) requestLocationUpdates(localListener) true } else false } } fun stopListeningLocation() { fun stopListeningLocation() { Loading @@ -170,7 +170,6 @@ class FakeLocationStateUseCase( } } fun requestLocationUpdates(listener: LocationListener) { fun requestLocationUpdates(listener: LocationListener) { acquireLocationPermission() try { try { locationManager.requestLocationUpdates( locationManager.requestLocationUpdates( LocationManager.NETWORK_PROVIDER, // TODO: tight this with fakelocation module. LocationManager.NETWORK_PROVIDER, // TODO: tight this with fakelocation module. Loading app/src/main/java/foundation/e/privacycentralapp/features/location/FakeLocationFragment.kt +32 −2 Original line number Original line Diff line number Diff line Loading @@ -17,6 +17,7 @@ package foundation.e.privacycentralapp.features.location package foundation.e.privacycentralapp.features.location import android.Manifest import android.annotation.SuppressLint import android.annotation.SuppressLint import android.content.Context import android.content.Context import android.location.Location import android.location.Location Loading @@ -24,6 +25,7 @@ import android.os.Bundle import android.text.Editable import android.text.Editable import android.view.View import android.view.View import android.widget.Toast import android.widget.Toast import androidx.activity.result.contract.ActivityResultContracts import androidx.annotation.NonNull import androidx.annotation.NonNull import androidx.core.view.isVisible import androidx.core.view.isVisible import androidx.core.widget.addTextChangedListener import androidx.core.widget.addTextChangedListener Loading Loading @@ -81,6 +83,16 @@ class FakeLocationFragment : NavToolbarFragment(R.layout.fragment_fake_location) private var inputJob: Job? = null private var inputJob: Job? = null private val locationPermissionRequest = registerForActivityResult( ActivityResultContracts.RequestMultiplePermissions() ) { permissions -> if (permissions.getOrDefault(Manifest.permission.ACCESS_FINE_LOCATION, false) || permissions.getOrDefault(Manifest.permission.ACCESS_COARSE_LOCATION, false) ) { viewModel.submitAction(Action.StartListeningLocation) } // TODO: else. } companion object { companion object { private const val DEBOUNCE_PERIOD = 1000L private const val DEBOUNCE_PERIOD = 1000L } } Loading Loading @@ -146,6 +158,14 @@ class FakeLocationFragment : NavToolbarFragment(R.layout.fragment_fake_location) is FakeLocationViewModel.SingleEvent.LocationUpdatedEvent -> { is FakeLocationViewModel.SingleEvent.LocationUpdatedEvent -> { updateLocation(event.location, event.mode) updateLocation(event.location, event.mode) } } is FakeLocationViewModel.SingleEvent.RequestLocationPermission -> { // TODO rationale dialog //shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION) locationPermissionRequest.launch(arrayOf( Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION )) } } } } } } } Loading @@ -158,6 +178,16 @@ class FakeLocationFragment : NavToolbarFragment(R.layout.fragment_fake_location) } } } } // val locationPermissionRequest = registerForActivityResult( // ActivityResultContracts.RequestMultiplePermissions() // ) { permissions -> // if (permissions.getOrDefault(Manifest.permission.ACCESS_FINE_LOCATION, false) // || permissions.getOrDefault(Manifest.permission.ACCESS_COARSE_LOCATION, false) // ) { // startLocationUpdates() // } // } private fun getCoordinatesAfterTextChanged( private fun getCoordinatesAfterTextChanged( inputLayout: TextInputLayout, inputLayout: TextInputLayout, editText: TextInputEditText, editText: TextInputEditText, Loading Loading @@ -325,13 +355,13 @@ class FakeLocationFragment : NavToolbarFragment(R.layout.fragment_fake_location) override fun onResume() { override fun onResume() { super.onResume() super.onResume() viewModel.submitAction(Action.EnterScreen) viewModel.submitAction(Action.StartListeningLocation) binding.mapView.onResume() binding.mapView.onResume() } } override fun onPause() { override fun onPause() { super.onPause() super.onPause() viewModel.submitAction(Action.LeaveScreen) viewModel.submitAction(Action.StopListeningLocation) binding.mapView.onPause() binding.mapView.onPause() } } Loading app/src/main/java/foundation/e/privacycentralapp/features/location/FakeLocationViewModel.kt +12 −4 Original line number Original line Diff line number Diff line Loading @@ -86,8 +86,8 @@ class FakeLocationViewModel( fun submitAction(action: Action) = viewModelScope.launch { fun submitAction(action: Action) = viewModelScope.launch { when (action) { when (action) { is Action.EnterScreen -> fakeLocationStateUseCase.startListeningLocation() is Action.StartListeningLocation -> actionStartListeningLocation() is Action.LeaveScreen -> fakeLocationStateUseCase.stopListeningLocation() is Action.StopListeningLocation -> fakeLocationStateUseCase.stopListeningLocation() is Action.SetSpecificLocationAction -> setSpecificLocation(action) is Action.SetSpecificLocationAction -> setSpecificLocation(action) is Action.UseRandomLocationAction -> fakeLocationStateUseCase.setRandomLocation() is Action.UseRandomLocationAction -> fakeLocationStateUseCase.setRandomLocation() is Action.UseRealLocationAction -> is Action.UseRealLocationAction -> Loading @@ -97,18 +97,26 @@ class FakeLocationViewModel( } } } } private suspend fun actionStartListeningLocation() { val started = fakeLocationStateUseCase.startListeningLocation() if (!started) { _singleEvents.emit(SingleEvent.RequestLocationPermission) } } private suspend fun setSpecificLocation(action: Action.SetSpecificLocationAction) { private suspend fun setSpecificLocation(action: Action.SetSpecificLocationAction) { specificLocationInputFlow.emit(action) specificLocationInputFlow.emit(action) } } sealed class SingleEvent { sealed class SingleEvent { data class LocationUpdatedEvent(val mode: LocationMode, val location: Location?) : SingleEvent() data class LocationUpdatedEvent(val mode: LocationMode, val location: Location?) : SingleEvent() object RequestLocationPermission: SingleEvent() data class ErrorEvent(val error: String) : SingleEvent() data class ErrorEvent(val error: String) : SingleEvent() } } sealed class Action { sealed class Action { object EnterScreen : Action() object StartListeningLocation : Action() object LeaveScreen : Action() object StopListeningLocation : Action() object UseRealLocationAction : Action() object UseRealLocationAction : Action() object UseRandomLocationAction : Action() object UseRandomLocationAction : Action() data class SetSpecificLocationAction( data class SetSpecificLocationAction( Loading build.gradle +1 −2 Original line number Original line Diff line number Diff line Loading @@ -41,7 +41,6 @@ buildscript { plugins { plugins { id 'com.diffplug.spotless' version '5.12.4' id 'com.diffplug.spotless' version '5.12.4' id 'com.github.ben-manes.versions' version '0.38.0' id 'com.github.ben-manes.versions' version '0.38.0' //id 'com.android.library' version '4.1.3' apply false id 'org.jetbrains.kotlin.android' version '1.6.10' apply false id 'org.jetbrains.kotlin.android' version '1.6.10' apply false } } Loading Loading @@ -130,7 +129,7 @@ subprojects { tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach { tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach { kotlinOptions { kotlinOptions { // Treat all Kotlin warnings as errors // Treat all Kotlin warnings as errors allWarningsAsErrors = true //allWarningsAsErrors = true freeCompilerArgs += "-Xopt-in=kotlinx.coroutines.ExperimentalCoroutinesApi" freeCompilerArgs += "-Xopt-in=kotlinx.coroutines.ExperimentalCoroutinesApi" // Set JVM target to 1.8 // Set JVM target to 1.8 Loading fakelocation/fakelocationdemo/.gitignore 0 → 100644 +1 −0 Original line number Original line Diff line number Diff line /build No newline at end of file Loading
app/src/main/java/foundation/e/privacycentralapp/domain/usecases/FakeLocationStateUseCase.kt +14 −15 Original line number Original line Diff line number Diff line Loading @@ -61,23 +61,15 @@ class FakeLocationStateUseCase( private val locationManager: LocationManager private val locationManager: LocationManager get() = appContext.getSystemService(Context.LOCATION_SERVICE) as LocationManager get() = appContext.getSystemService(Context.LOCATION_SERVICE) as LocationManager private fun acquireLocationPermission() { private fun acquireLocationPermission(): Boolean { if (appContext.checkSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { return (appContext.checkSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) permissionsModule.toggleDangerousPermission( || false // TODO : should return true / false. permissionsModule.toggleDangerousPermission(appDesc, android.Manifest.permission.ACCESS_FINE_LOCATION, true) appDesc, android.Manifest.permission.ACCESS_FINE_LOCATION, true ) } } } private fun applySettings(isQuickPrivacyEnabled: Boolean, fakeLocation: Pair<Float, Float>?, isSpecificLocation: Boolean = false) { private fun applySettings(isQuickPrivacyEnabled: Boolean, fakeLocation: Pair<Float, Float>?, isSpecificLocation: Boolean = false) { _configuredLocationMode.value = computeLocationMode(fakeLocation, isSpecificLocation) _configuredLocationMode.value = computeLocationMode(fakeLocation, isSpecificLocation) if (isQuickPrivacyEnabled && fakeLocation != null) { if (isQuickPrivacyEnabled && fakeLocation != null && acquireMockLocationPermission()) { if (permissionsModule.getAppOpMode(appDesc, AppOpsManager.OPSTR_MOCK_LOCATION) != AppOpModes.ALLOWED) { permissionsModule.setAppOpMode(appDesc, AppOpsManager.OPSTR_MOCK_LOCATION, AppOpModes.ALLOWED) } fakeLocationModule.startFakeLocation() fakeLocationModule.startFakeLocation() fakeLocationModule.setFakeLocation(fakeLocation.first.toDouble(), fakeLocation.second.toDouble()) fakeLocationModule.setFakeLocation(fakeLocation.first.toDouble(), fakeLocation.second.toDouble()) localStateRepository.locationMode.value = configuredLocationMode.value.first localStateRepository.locationMode.value = configuredLocationMode.value.first Loading @@ -87,6 +79,11 @@ class FakeLocationStateUseCase( } } } } private fun acquireMockLocationPermission(): Boolean { return (permissionsModule.getAppOpMode(appDesc, AppOpsManager.OPSTR_MOCK_LOCATION) == AppOpModes.ALLOWED) || permissionsModule.setAppOpMode(appDesc, AppOpsManager.OPSTR_MOCK_LOCATION, AppOpModes.ALLOWED) == null } fun setSpecificLocation(latitude: Float, longitude: Float) { fun setSpecificLocation(latitude: Float, longitude: Float) { if (!localStateRepository.isQuickPrivacyEnabled) { if (!localStateRepository.isQuickPrivacyEnabled) { localStateRepository.setShowQuickPrivacyDisabledMessage(true) localStateRepository.setShowQuickPrivacyDisabledMessage(true) Loading Loading @@ -161,8 +158,11 @@ class FakeLocationStateUseCase( } } } } fun startListeningLocation() { fun startListeningLocation(): Boolean { return if (acquireLocationPermission()) { requestLocationUpdates(localListener) requestLocationUpdates(localListener) true } else false } } fun stopListeningLocation() { fun stopListeningLocation() { Loading @@ -170,7 +170,6 @@ class FakeLocationStateUseCase( } } fun requestLocationUpdates(listener: LocationListener) { fun requestLocationUpdates(listener: LocationListener) { acquireLocationPermission() try { try { locationManager.requestLocationUpdates( locationManager.requestLocationUpdates( LocationManager.NETWORK_PROVIDER, // TODO: tight this with fakelocation module. LocationManager.NETWORK_PROVIDER, // TODO: tight this with fakelocation module. Loading
app/src/main/java/foundation/e/privacycentralapp/features/location/FakeLocationFragment.kt +32 −2 Original line number Original line Diff line number Diff line Loading @@ -17,6 +17,7 @@ package foundation.e.privacycentralapp.features.location package foundation.e.privacycentralapp.features.location import android.Manifest import android.annotation.SuppressLint import android.annotation.SuppressLint import android.content.Context import android.content.Context import android.location.Location import android.location.Location Loading @@ -24,6 +25,7 @@ import android.os.Bundle import android.text.Editable import android.text.Editable import android.view.View import android.view.View import android.widget.Toast import android.widget.Toast import androidx.activity.result.contract.ActivityResultContracts import androidx.annotation.NonNull import androidx.annotation.NonNull import androidx.core.view.isVisible import androidx.core.view.isVisible import androidx.core.widget.addTextChangedListener import androidx.core.widget.addTextChangedListener Loading Loading @@ -81,6 +83,16 @@ class FakeLocationFragment : NavToolbarFragment(R.layout.fragment_fake_location) private var inputJob: Job? = null private var inputJob: Job? = null private val locationPermissionRequest = registerForActivityResult( ActivityResultContracts.RequestMultiplePermissions() ) { permissions -> if (permissions.getOrDefault(Manifest.permission.ACCESS_FINE_LOCATION, false) || permissions.getOrDefault(Manifest.permission.ACCESS_COARSE_LOCATION, false) ) { viewModel.submitAction(Action.StartListeningLocation) } // TODO: else. } companion object { companion object { private const val DEBOUNCE_PERIOD = 1000L private const val DEBOUNCE_PERIOD = 1000L } } Loading Loading @@ -146,6 +158,14 @@ class FakeLocationFragment : NavToolbarFragment(R.layout.fragment_fake_location) is FakeLocationViewModel.SingleEvent.LocationUpdatedEvent -> { is FakeLocationViewModel.SingleEvent.LocationUpdatedEvent -> { updateLocation(event.location, event.mode) updateLocation(event.location, event.mode) } } is FakeLocationViewModel.SingleEvent.RequestLocationPermission -> { // TODO rationale dialog //shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION) locationPermissionRequest.launch(arrayOf( Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION )) } } } } } } } Loading @@ -158,6 +178,16 @@ class FakeLocationFragment : NavToolbarFragment(R.layout.fragment_fake_location) } } } } // val locationPermissionRequest = registerForActivityResult( // ActivityResultContracts.RequestMultiplePermissions() // ) { permissions -> // if (permissions.getOrDefault(Manifest.permission.ACCESS_FINE_LOCATION, false) // || permissions.getOrDefault(Manifest.permission.ACCESS_COARSE_LOCATION, false) // ) { // startLocationUpdates() // } // } private fun getCoordinatesAfterTextChanged( private fun getCoordinatesAfterTextChanged( inputLayout: TextInputLayout, inputLayout: TextInputLayout, editText: TextInputEditText, editText: TextInputEditText, Loading Loading @@ -325,13 +355,13 @@ class FakeLocationFragment : NavToolbarFragment(R.layout.fragment_fake_location) override fun onResume() { override fun onResume() { super.onResume() super.onResume() viewModel.submitAction(Action.EnterScreen) viewModel.submitAction(Action.StartListeningLocation) binding.mapView.onResume() binding.mapView.onResume() } } override fun onPause() { override fun onPause() { super.onPause() super.onPause() viewModel.submitAction(Action.LeaveScreen) viewModel.submitAction(Action.StopListeningLocation) binding.mapView.onPause() binding.mapView.onPause() } } Loading
app/src/main/java/foundation/e/privacycentralapp/features/location/FakeLocationViewModel.kt +12 −4 Original line number Original line Diff line number Diff line Loading @@ -86,8 +86,8 @@ class FakeLocationViewModel( fun submitAction(action: Action) = viewModelScope.launch { fun submitAction(action: Action) = viewModelScope.launch { when (action) { when (action) { is Action.EnterScreen -> fakeLocationStateUseCase.startListeningLocation() is Action.StartListeningLocation -> actionStartListeningLocation() is Action.LeaveScreen -> fakeLocationStateUseCase.stopListeningLocation() is Action.StopListeningLocation -> fakeLocationStateUseCase.stopListeningLocation() is Action.SetSpecificLocationAction -> setSpecificLocation(action) is Action.SetSpecificLocationAction -> setSpecificLocation(action) is Action.UseRandomLocationAction -> fakeLocationStateUseCase.setRandomLocation() is Action.UseRandomLocationAction -> fakeLocationStateUseCase.setRandomLocation() is Action.UseRealLocationAction -> is Action.UseRealLocationAction -> Loading @@ -97,18 +97,26 @@ class FakeLocationViewModel( } } } } private suspend fun actionStartListeningLocation() { val started = fakeLocationStateUseCase.startListeningLocation() if (!started) { _singleEvents.emit(SingleEvent.RequestLocationPermission) } } private suspend fun setSpecificLocation(action: Action.SetSpecificLocationAction) { private suspend fun setSpecificLocation(action: Action.SetSpecificLocationAction) { specificLocationInputFlow.emit(action) specificLocationInputFlow.emit(action) } } sealed class SingleEvent { sealed class SingleEvent { data class LocationUpdatedEvent(val mode: LocationMode, val location: Location?) : SingleEvent() data class LocationUpdatedEvent(val mode: LocationMode, val location: Location?) : SingleEvent() object RequestLocationPermission: SingleEvent() data class ErrorEvent(val error: String) : SingleEvent() data class ErrorEvent(val error: String) : SingleEvent() } } sealed class Action { sealed class Action { object EnterScreen : Action() object StartListeningLocation : Action() object LeaveScreen : Action() object StopListeningLocation : Action() object UseRealLocationAction : Action() object UseRealLocationAction : Action() object UseRandomLocationAction : Action() object UseRandomLocationAction : Action() data class SetSpecificLocationAction( data class SetSpecificLocationAction( Loading
build.gradle +1 −2 Original line number Original line Diff line number Diff line Loading @@ -41,7 +41,6 @@ buildscript { plugins { plugins { id 'com.diffplug.spotless' version '5.12.4' id 'com.diffplug.spotless' version '5.12.4' id 'com.github.ben-manes.versions' version '0.38.0' id 'com.github.ben-manes.versions' version '0.38.0' //id 'com.android.library' version '4.1.3' apply false id 'org.jetbrains.kotlin.android' version '1.6.10' apply false id 'org.jetbrains.kotlin.android' version '1.6.10' apply false } } Loading Loading @@ -130,7 +129,7 @@ subprojects { tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach { tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach { kotlinOptions { kotlinOptions { // Treat all Kotlin warnings as errors // Treat all Kotlin warnings as errors allWarningsAsErrors = true //allWarningsAsErrors = true freeCompilerArgs += "-Xopt-in=kotlinx.coroutines.ExperimentalCoroutinesApi" freeCompilerArgs += "-Xopt-in=kotlinx.coroutines.ExperimentalCoroutinesApi" // Set JVM target to 1.8 // Set JVM target to 1.8 Loading
fakelocation/fakelocationdemo/.gitignore 0 → 100644 +1 −0 Original line number Original line Diff line number Diff line /build No newline at end of file