diff options
author | Leonard Kugis <leonard@kug.is> | 2023-12-23 00:52:30 +0100 |
---|---|---|
committer | Leonard Kugis <leonard@kug.is> | 2023-12-23 00:52:30 +0100 |
commit | eab77a885f6cca1d785ca57c4cd9182dc1a898cf (patch) | |
tree | 7dba714b870895220d815368d7762212ff10c5eb /app/src/main | |
parent | 98df413858d1ac577f9c510a9490f382b3f848b4 (diff) |
Implemented altitude/speed/jitter parameters
Diffstat (limited to 'app/src/main')
7 files changed, 229 insertions, 13 deletions
diff --git a/app/src/main/java/foundation/e/advancedprivacy/data/repositories/LocalStateRepository.kt b/app/src/main/java/foundation/e/advancedprivacy/data/repositories/LocalStateRepository.kt index 2afd6ee..fd309a6 100644 --- a/app/src/main/java/foundation/e/advancedprivacy/data/repositories/LocalStateRepository.kt +++ b/app/src/main/java/foundation/e/advancedprivacy/data/repositories/LocalStateRepository.kt @@ -35,6 +35,9 @@ class LocalStateRepositoryImpl(context: Context) : LocalStateRepository { private const val SHARED_PREFS_FILE = "localState" private const val KEY_BLOCK_TRACKERS = "blockTrackers" private const val KEY_IP_SCRAMBLING = "ipScrambling" + private const val KEY_FAKE_ALTITUDE = "fakeAltitude" + private const val KEY_FAKE_SPEED = "fakeSpeed" + private const val KEY_FAKE_JITTER = "fakeJitter" private const val KEY_FAKE_LOCATION = "fakeLocation" private const val KEY_FAKE_LATITUDE = "fakeLatitude" private const val KEY_FAKE_LONGITUDE = "fakeLongitude" @@ -66,6 +69,30 @@ class LocalStateRepositoryImpl(context: Context) : LocalStateRepository { _fakeLocationEnabled.update { enabled } } + override var fakeAltitude: Float + get() = sharedPref.getFloat(KEY_FAKE_ALTITUDE, 3.0f) + set(value) { + sharedPref.edit() + .putFloat(KEY_FAKE_ALTITUDE, value) + .apply() + } + + override var fakeSpeed: Float + get() = sharedPref.getFloat(KEY_FAKE_SPEED, 1.0f) + set(value) { + sharedPref.edit() + .putFloat(KEY_FAKE_SPEED, value) + .apply() + } + + override var fakeJitter: Float + get() = sharedPref.getFloat(KEY_FAKE_JITTER, 3.0f) + set(value) { + sharedPref.edit() + .putFloat(KEY_FAKE_JITTER, value) + .apply() + } + override var fakeLocation: Pair<Float, Float> get() = Pair( // Initial default value is Quezon City diff --git a/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/FakeLocationStateUseCase.kt b/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/FakeLocationStateUseCase.kt index 282116e..8cf5f43 100644 --- a/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/FakeLocationStateUseCase.kt +++ b/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/FakeLocationStateUseCase.kt @@ -32,6 +32,7 @@ import foundation.e.advancedprivacy.domain.repositories.LocalStateRepository import foundation.e.advancedprivacy.dummy.CityDataSource import foundation.e.advancedprivacy.externalinterfaces.permissions.IPermissionsPrivacyModule import foundation.e.advancedprivacy.fakelocation.domain.usecases.FakeLocationModule +import foundation.e.advancedprivacy.features.location.FakeLocationState import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -49,11 +50,11 @@ class FakeLocationStateUseCase( private val appContext: Context, coroutineScope: CoroutineScope ) { - private val _configuredLocationMode = MutableStateFlow<Triple<LocationMode, Float?, Float?>>( - Triple(LocationMode.REAL_LOCATION, null, null) + private val _configuredLocationMode = MutableStateFlow<FakeLocationState>( + FakeLocationState(LocationMode.REAL_LOCATION, null, null, null, null, false, null, null, false) ) - val configuredLocationMode: StateFlow<Triple<LocationMode, Float?, Float?>> = _configuredLocationMode + val configuredLocationMode: StateFlow<FakeLocationState> = _configuredLocationMode init { coroutineScope.launch { @@ -76,8 +77,8 @@ class FakeLocationStateUseCase( if (isEnabled && hasAcquireMockLocationPermission()) { fakeLocationModule.startFakeLocation() - fakeLocationModule.setFakeLocation(fakeLocation.first.toDouble(), fakeLocation.second.toDouble()) - localStateRepository.locationMode.value = configuredLocationMode.value.first + fakeLocationModule.setFakeLocation(localStateRepository.fakeAltitude.toDouble(), localStateRepository.fakeSpeed, localStateRepository.fakeJitter, fakeLocation.first.toDouble(), fakeLocation.second.toDouble()) + localStateRepository.locationMode.value = configuredLocationMode.value.mode } else { fakeLocationModule.stopFakeLocation() localStateRepository.locationMode.value = LocationMode.REAL_LOCATION @@ -89,6 +90,12 @@ class FakeLocationStateUseCase( permissionsModule.setAppOpMode(appDesc, AppOpsManager.OPSTR_MOCK_LOCATION, AppOpModes.ALLOWED) } + fun setFakeLocationParameters(altitude: Float, speed: Float, jitter: Float) { + localStateRepository.fakeAltitude = altitude + localStateRepository.fakeSpeed = speed + localStateRepository.fakeJitter = jitter + } + fun setSpecificLocation(latitude: Float, longitude: Float) { setFakeLocation(latitude to longitude, true) } @@ -115,16 +122,22 @@ class FakeLocationStateUseCase( isFakeLocationEnabled: Boolean, fakeLocation: Pair<Float, Float>, isSpecificLocation: Boolean = false, - ): Triple<LocationMode, Float?, Float?> { - return Triple( + ): FakeLocationState { + return FakeLocationState( when { !isFakeLocationEnabled -> LocationMode.REAL_LOCATION (fakeLocation in citiesRepository.citiesLocationsList && !isSpecificLocation) -> LocationMode.RANDOM_LOCATION else -> LocationMode.SPECIFIC_LOCATION }, + null, + null, + null, + null, + false, fakeLocation.first, - fakeLocation.second + fakeLocation.second, + false ) } diff --git a/app/src/main/java/foundation/e/advancedprivacy/features/location/FakeLocationFragment.kt b/app/src/main/java/foundation/e/advancedprivacy/features/location/FakeLocationFragment.kt index 1c629c2..2b054ab 100644 --- a/app/src/main/java/foundation/e/advancedprivacy/features/location/FakeLocationFragment.kt +++ b/app/src/main/java/foundation/e/advancedprivacy/features/location/FakeLocationFragment.kt @@ -244,6 +244,31 @@ class FakeLocationFragment : NavToolbarFragment(R.layout.fragment_fake_location) } } + private fun updateMockLocationParameters() { + viewModel.submitAction( + Action.UpdateMockLocationParameters( + binding.altitude.text.toString().toFloat(), + binding.speed.text.toString().toFloat(), + binding.jitter.text.toString().toFloat(), + ) + ) + } + + @Suppress("UNUSED_PARAMETER") + private fun onAltitudeTextChanged(editable: Editable?) { + updateMockLocationParameters() + } + + @Suppress("UNUSED_PARAMETER") + private fun onSpeedTextChanged(editable: Editable?) { + updateMockLocationParameters() + } + + @Suppress("UNUSED_PARAMETER") + private fun onJitterTextChanged(editable: Editable?) { + updateMockLocationParameters() + } + @Suppress("UNUSED_PARAMETER") private fun onLatTextChanged(editable: Editable?) { if (!binding.edittextLatitude.isFocused || @@ -291,6 +316,9 @@ class FakeLocationFragment : NavToolbarFragment(R.layout.fragment_fake_location) } } + binding.altitude.addTextChangedListener(afterTextChanged = ::onAltitudeTextChanged) + binding.speed.addTextChangedListener(afterTextChanged = ::onSpeedTextChanged) + binding.jitter.addTextChangedListener(afterTextChanged = ::onJitterTextChanged) binding.edittextLatitude.addTextChangedListener(afterTextChanged = ::onLatTextChanged) binding.edittextLongitude.addTextChangedListener(afterTextChanged = ::onLonTextChanged) binding.edittextLatitude.onFocusChangeListener = latLonOnFocusChangeListener @@ -307,6 +335,19 @@ class FakeLocationFragment : NavToolbarFragment(R.layout.fragment_fake_location) binding.mapView.isEnabled = (state.mode == LocationMode.SPECIFIC_LOCATION) + binding.altitude.isEnabled = state.mode == LocationMode.SPECIFIC_LOCATION + binding.speed.isEnabled = state.mode == LocationMode.SPECIFIC_LOCATION + binding.jitter.isEnabled = state.mode == LocationMode.SPECIFIC_LOCATION + + if(!binding.altitude.isFocused) + binding.altitude.setText(state.altitude?.toString()) + + if(!binding.speed.isFocused) + binding.speed.setText(state.speed?.toString()) + + if(!binding.jitter.isFocused) + binding.jitter.setText(state.jitter?.toString()) + if (state.mode == LocationMode.REAL_LOCATION) { binding.centeredMarker.isVisible = false } else { diff --git a/app/src/main/java/foundation/e/advancedprivacy/features/location/FakeLocationState.kt b/app/src/main/java/foundation/e/advancedprivacy/features/location/FakeLocationState.kt index baa672b..12ebecf 100644 --- a/app/src/main/java/foundation/e/advancedprivacy/features/location/FakeLocationState.kt +++ b/app/src/main/java/foundation/e/advancedprivacy/features/location/FakeLocationState.kt @@ -23,6 +23,10 @@ import foundation.e.advancedprivacy.domain.entities.LocationMode data class FakeLocationState( val mode: LocationMode = LocationMode.REAL_LOCATION, val currentLocation: Location? = null, + val altitude: Float? = null, + val speed: Float? = null, + val jitter: Float? = null, + val joystick: Boolean = false, val specificLatitude: Float? = null, val specificLongitude: Float? = null, val forceRefresh: Boolean = false, diff --git a/app/src/main/java/foundation/e/advancedprivacy/features/location/FakeLocationViewModel.kt b/app/src/main/java/foundation/e/advancedprivacy/features/location/FakeLocationViewModel.kt index deca4c1..29bfbfa 100644 --- a/app/src/main/java/foundation/e/advancedprivacy/features/location/FakeLocationViewModel.kt +++ b/app/src/main/java/foundation/e/advancedprivacy/features/location/FakeLocationViewModel.kt @@ -52,24 +52,32 @@ class FakeLocationViewModel( val singleEvents = _singleEvents.asSharedFlow() private val specificLocationInputFlow = MutableSharedFlow<Action.SetSpecificLocationAction>() + private val mockLocationParametersInputFlow = MutableSharedFlow<Action.UpdateMockLocationParameters>() @OptIn(FlowPreview::class) suspend fun doOnStartedState() = withContext(Dispatchers.Main) { launch { merge( - fakeLocationStateUseCase.configuredLocationMode.map { (mode, lat, lon) -> + fakeLocationStateUseCase.configuredLocationMode.map { ss -> _state.update { s -> s.copy( - mode = mode, - specificLatitude = lat, - specificLongitude = lon + mode = ss.mode, + altitude = ss.altitude, + speed = ss.speed, + jitter = ss.jitter, + specificLatitude = ss.specificLatitude, + specificLongitude = ss.specificLongitude ) } }, specificLocationInputFlow .debounce(SET_SPECIFIC_LOCATION_DELAY).map { action -> fakeLocationStateUseCase.setSpecificLocation(action.latitude, action.longitude) - } + }, + mockLocationParametersInputFlow + .debounce(SET_SPECIFIC_LOCATION_DELAY).map { action -> + fakeLocationStateUseCase.setFakeLocationParameters(action.altitude, action.speed, action.jitter) + }, ).collect {} } } @@ -82,6 +90,8 @@ class FakeLocationViewModel( is Action.UseRandomLocationAction -> fakeLocationStateUseCase.setRandomLocation() is Action.UseRealLocationAction -> fakeLocationStateUseCase.stopFakeLocation() + is Action.UpdateMockLocationParameters -> updateMockLocationParameters(action) + is Action.UseJoystick -> enableJoystick() } } @@ -96,6 +106,14 @@ class FakeLocationViewModel( specificLocationInputFlow.emit(action) } + private suspend fun updateMockLocationParameters(action: Action.UpdateMockLocationParameters) { + mockLocationParametersInputFlow.emit(action) + } + + private suspend fun enableJoystick() { + + } + sealed class SingleEvent { object RequestLocationPermission : SingleEvent() data class ErrorEvent(val error: String) : SingleEvent() @@ -106,6 +124,12 @@ class FakeLocationViewModel( object StopListeningLocation : Action() object UseRealLocationAction : Action() object UseRandomLocationAction : Action() + object UseJoystick : Action() + data class UpdateMockLocationParameters( + val altitude: Float, + val speed: Float, + val jitter: Float + ) : Action() data class SetSpecificLocationAction( val latitude: Float, val longitude: Float diff --git a/app/src/main/res/layout/fragment_fake_location.xml b/app/src/main/res/layout/fragment_fake_location.xml index 5da95e1..47ed7da 100644 --- a/app/src/main/res/layout/fragment_fake_location.xml +++ b/app/src/main/res/layout/fragment_fake_location.xml @@ -83,6 +83,109 @@ /> </RadioGroup> + <LinearLayout + android:layout_height="match_parent" + android:padding="16dp" + android:layout_width="match_parent" + android:orientation="horizontal" + tools:context=".main.MainActivity" + > + + <TextView + android:id="@+id/fake_location_info_altitude" + android:layout_gravity="center_horizontal" + android:layout_height="wrap_content" + android:layout_width="0dp" + android:text="@string/location_altitude" + android:lineSpacingExtra="5sp" + /> + + <EditText + android:id="@+id/altitude" + android:inputType="numberDecimal" + android:layout_width="wrap_content" + android:layout_height="24dp" + /> + + </LinearLayout> + + <LinearLayout + android:layout_height="match_parent" + android:padding="16dp" + android:layout_width="match_parent" + android:orientation="horizontal" + tools:context=".main.MainActivity" + > + + <TextView + android:id="@+id/fake_location_info_speed" + android:layout_gravity="center_horizontal" + android:layout_height="wrap_content" + android:layout_width="0dp" + android:text="@string/location_speed" + android:lineSpacingExtra="5sp" + /> + + <EditText + android:id="@+id/speed" + android:inputType="numberDecimal" + android:layout_width="wrap_content" + android:layout_height="24dp" + /> + + </LinearLayout> + + <LinearLayout + android:layout_height="match_parent" + android:padding="16dp" + android:layout_width="match_parent" + android:orientation="horizontal" + tools:context=".main.MainActivity" + > + + <TextView + android:id="@+id/fake_location_info_jitter" + android:layout_gravity="center_horizontal" + android:layout_height="wrap_content" + android:layout_width="0dp" + android:text="@string/location_jitter" + android:lineSpacingExtra="5sp" + /> + + <EditText + android:id="@+id/jitter" + android:inputType="numberDecimal" + android:layout_width="wrap_content" + android:layout_height="24dp" + /> + + </LinearLayout> + + <LinearLayout + android:layout_height="match_parent" + android:padding="16dp" + android:layout_width="match_parent" + android:orientation="horizontal" + tools:context=".main.MainActivity" + > + + <TextView + android:id="@+id/fake_location_info_joystick" + android:layout_gravity="center_horizontal" + android:layout_height="wrap_content" + android:layout_width="0dp" + android:text="@string/location_joystick" + android:lineSpacingExtra="5sp" + /> + + <Switch + android:id="@+id/joystick_enable" + android:layout_width="wrap_content" + android:layout_height="24dp" + android:checked="true" + /> + + </LinearLayout> <FrameLayout android:layout_marginTop="16dp" diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index aa33837..416a0d2 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -82,6 +82,10 @@ <!-- Location --> <string name="location_title" weblate_ctx="location-1">Manage my location</string> <string name="location_info" weblate_ctx="location-1">Your location can reveal a lot about yourself or your activities.\n\nManage my location enables you to use a fake location instead of your real position. This way, your real location isn\'t shared with applications that might be snooping too much.</string> + <string name="location_altitude">Altitude [m]</string> + <string name="location_speed">Speed [km/h]</string> + <string name="location_jitter">Jitter [m]</string> + <string name="location_joystick">Enable joystick</string> <string name="location_use_real_location" weblate_ctx="location-1">Use my real location</string> <string name="location_use_random_location" weblate_ctx="location-1">Use a random plausible location</string> <string name="location_use_specific_location" weblate_ctx="location-1">Use a specific location</string> |