Loading app/src/main/java/foundation/e/privacycentralapp/DependencyContainer.kt +2 −2 Original line number Diff line number Diff line Loading @@ -78,7 +78,7 @@ class DependencyContainer(val app: Application) { // Usecases val getQuickPrivacyStateUseCase by lazy { GetQuickPrivacyStateUseCase(localStateRepository) GetQuickPrivacyStateUseCase(localStateRepository, GlobalScope) } private val ipScramblingStateUseCase by lazy { IpScramblingStateUseCase( Loading Loading @@ -119,7 +119,7 @@ class DependencyContainer(val app: Application) { } val trackersViewModelFactory by lazy { TrackersViewModelFactory(trackersStatisticsUseCase) TrackersViewModelFactory(getQuickPrivacyStateUseCase, trackersStatisticsUseCase) } val appTrackersViewModelFactory by lazy { Loading app/src/main/java/foundation/e/privacycentralapp/common/QuickPrivacyDisabledSnackbar.kt 0 → 100644 +36 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 E FOUNDATION * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. */ package foundation.e.privacycentralapp.common import android.view.View import com.google.android.material.snackbar.BaseTransientBottomBar import com.google.android.material.snackbar.Snackbar import foundation.e.privacycentralapp.R fun initQuickPrivacySnackbar(view: View, onDismiss: () -> Unit): Snackbar { val snackbar = Snackbar.make(view, R.string.quickprivacy_disabled_message, Snackbar.LENGTH_INDEFINITE) snackbar.setAction(R.string.close) { onDismiss() } snackbar.addCallback(object : BaseTransientBottomBar.BaseCallback<Snackbar>() { override fun onDismissed(transientBottomBar: Snackbar?, event: Int) { super.onDismissed(transientBottomBar, event) if (event == DISMISS_EVENT_SWIPE) onDismiss() } }) return snackbar } app/src/main/java/foundation/e/privacycentralapp/data/repositories/LocalStateRepository.kt +8 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import foundation.e.privacycentralapp.domain.entities.InternetPrivacyMode import foundation.e.privacycentralapp.domain.entities.LocationMode import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow class LocalStateRepository(context: Context) { companion object { Loading Loading @@ -84,6 +85,13 @@ class LocalStateRepository(context: Context) { val internetPrivacyMode: MutableStateFlow<InternetPrivacyMode> = MutableStateFlow(InternetPrivacyMode.REAL_IP) private val _showQuickPrivacyDisabledMessage = MutableStateFlow(false) val showQuickPrivacyDisabledMessage: StateFlow<Boolean> = _showQuickPrivacyDisabledMessage fun setShowQuickPrivacyDisabledMessage(show: Boolean) { _showQuickPrivacyDisabledMessage.value = show } var firstBoot: Boolean get() = sharedPref.getBoolean(KEY_FIRST_BOOT, true) set(value) = set(KEY_FIRST_BOOT, value) Loading app/src/main/java/foundation/e/privacycentralapp/domain/usecases/FakeLocationStateUseCase.kt +31 −28 Original line number Diff line number Diff line Loading @@ -33,6 +33,7 @@ import foundation.e.privacymodules.permissions.data.AppOpModes 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.collect import kotlinx.coroutines.launch import kotlin.random.Random Loading @@ -46,8 +47,8 @@ class FakeLocationStateUseCase( private val appContext: Context, private val coroutineScope: CoroutineScope ) { // private val _locationMode = MutableStateFlow(LocationMode.REAL_LOCATION) // val locationMode: StateFlow<LocationMode> = _locationMode private val _configuredLocationMode = MutableStateFlow<Triple<LocationMode, Float?, Float?>>(Triple(LocationMode.REAL_LOCATION, null, null)) val configuredLocationMode: StateFlow<Triple<LocationMode, Float?, Float?>> = _configuredLocationMode init { coroutineScope.launch { Loading @@ -60,44 +61,23 @@ class FakeLocationStateUseCase( private val locationManager: LocationManager get() = appContext.getSystemService(Context.LOCATION_SERVICE) as LocationManager fun getLocationMode(): Triple<LocationMode, Float?, Float?> { val fakeLocation = localStateRepository.fakeLocation return if (fakeLocation != null && localStateRepository.locationMode.value == LocationMode.SPECIFIC_LOCATION) { Triple( LocationMode.SPECIFIC_LOCATION, fakeLocation.first, fakeLocation.second ) } else { Triple(localStateRepository.locationMode.value, null, null) } } private fun acquireLocationPermission() { permissionsModule.toggleDangerousPermission( appDesc, android.Manifest.permission.ACCESS_FINE_LOCATION, true ) // permissionsModule.setAppOpMode( // appDesc, AppOpsManager.OPSTR_COARSE_LOCATION, // AppOpModes.ALLOWED // ) // permissionsModule.setAppOpMode( // appDesc, AppOpsManager.OPSTR_FINE_LOCATION, // AppOpModes.ALLOWED // ) } private fun applySettings(isQuickPrivacyEnabled: Boolean, fakeLocation: Pair<Float, Float>?) { _configuredLocationMode.value = computeLocationMode(fakeLocation) if (isQuickPrivacyEnabled && fakeLocation != null) { if (permissionsModule.getAppOpMode(appDesc, AppOpsManager.OPSTR_MOCK_LOCATION) != AppOpModes.ALLOWED) { permissionsModule.setAppOpMode(appDesc, AppOpsManager.OPSTR_MOCK_LOCATION, AppOpModes.ALLOWED) } fakeLocationModule.startFakeLocation() fakeLocationModule.setFakeLocation(fakeLocation.first.toDouble(), fakeLocation.second.toDouble()) localStateRepository.locationMode.value = if (fakeLocation in citiesRepository.citiesLocationsList) LocationMode.RANDOM_LOCATION else LocationMode.SPECIFIC_LOCATION localStateRepository.locationMode.value = configuredLocationMode.value.first } else { fakeLocationModule.stopFakeLocation() localStateRepository.locationMode.value = LocationMode.REAL_LOCATION Loading @@ -105,10 +85,18 @@ class FakeLocationStateUseCase( } fun setSpecificLocation(latitude: Float, longitude: Float) { if (!localStateRepository.isQuickPrivacyEnabled) { localStateRepository.setShowQuickPrivacyDisabledMessage(true) } setFakeLocation(latitude to longitude) } fun setRandomLocation() { if (!localStateRepository.isQuickPrivacyEnabled) { localStateRepository.setShowQuickPrivacyDisabledMessage(true) } val randomIndex = Random.nextInt(citiesRepository.citiesLocationsList.size) val location = citiesRepository.citiesLocationsList[randomIndex] Loading @@ -117,12 +105,27 @@ class FakeLocationStateUseCase( private fun setFakeLocation(location: Pair<Float, Float>) { localStateRepository.fakeLocation = location applySettings(true, location) applySettings(localStateRepository.isQuickPrivacyEnabled, location) } fun stopFakeLocation() { if (!localStateRepository.isQuickPrivacyEnabled) { localStateRepository.setShowQuickPrivacyDisabledMessage(true) } localStateRepository.fakeLocation = null applySettings(true, null) applySettings(localStateRepository.isQuickPrivacyEnabled, null) } private fun computeLocationMode(fakeLocation: Pair<Float, Float>?): Triple<LocationMode, Float?, Float?> { return Triple( when { fakeLocation == null -> LocationMode.REAL_LOCATION fakeLocation in citiesRepository.citiesLocationsList -> LocationMode.RANDOM_LOCATION else -> LocationMode.SPECIFIC_LOCATION }, fakeLocation?.first, fakeLocation?.second ) } val currentLocation = MutableStateFlow<Location?>(null) Loading app/src/main/java/foundation/e/privacycentralapp/domain/usecases/GetQuickPrivacyStateUseCase.kt +22 −2 Original line number Diff line number Diff line Loading @@ -21,12 +21,26 @@ import foundation.e.privacycentralapp.data.repositories.LocalStateRepository import foundation.e.privacycentralapp.domain.entities.InternetPrivacyMode import foundation.e.privacycentralapp.domain.entities.LocationMode import foundation.e.privacycentralapp.domain.entities.QuickPrivacyState import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.combine import kotlinx.coroutines.launch class GetQuickPrivacyStateUseCase( private val localStateRepository: LocalStateRepository, private val coroutineScope: CoroutineScope ) { init { coroutineScope.launch { localStateRepository.quickPrivacyEnabledFlow.collect { if (it) resetQuickPrivacyDisabledMessage() } } } class GetQuickPrivacyStateUseCase(private val localStateRepository: LocalStateRepository) { val quickPrivacyEnabledFlow = localStateRepository.quickPrivacyEnabledFlow val isQuickPrivacyEnabled get() = localStateRepository.isQuickPrivacyEnabled val quickPrivacyState = combine( localStateRepository.quickPrivacyEnabledFlow, Loading Loading @@ -77,4 +91,10 @@ class GetQuickPrivacyStateUseCase(private val localStateRepository: LocalStateRe val newState = !localStateRepository.isQuickPrivacyEnabled return localStateRepository.setQuickPrivacyReturnIsFirstActivation(newState) } val showQuickPrivacyDisabledMessage: StateFlow<Boolean> = localStateRepository.showQuickPrivacyDisabledMessage fun resetQuickPrivacyDisabledMessage() { localStateRepository.setShowQuickPrivacyDisabledMessage(false) } } Loading
app/src/main/java/foundation/e/privacycentralapp/DependencyContainer.kt +2 −2 Original line number Diff line number Diff line Loading @@ -78,7 +78,7 @@ class DependencyContainer(val app: Application) { // Usecases val getQuickPrivacyStateUseCase by lazy { GetQuickPrivacyStateUseCase(localStateRepository) GetQuickPrivacyStateUseCase(localStateRepository, GlobalScope) } private val ipScramblingStateUseCase by lazy { IpScramblingStateUseCase( Loading Loading @@ -119,7 +119,7 @@ class DependencyContainer(val app: Application) { } val trackersViewModelFactory by lazy { TrackersViewModelFactory(trackersStatisticsUseCase) TrackersViewModelFactory(getQuickPrivacyStateUseCase, trackersStatisticsUseCase) } val appTrackersViewModelFactory by lazy { Loading
app/src/main/java/foundation/e/privacycentralapp/common/QuickPrivacyDisabledSnackbar.kt 0 → 100644 +36 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 E FOUNDATION * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. */ package foundation.e.privacycentralapp.common import android.view.View import com.google.android.material.snackbar.BaseTransientBottomBar import com.google.android.material.snackbar.Snackbar import foundation.e.privacycentralapp.R fun initQuickPrivacySnackbar(view: View, onDismiss: () -> Unit): Snackbar { val snackbar = Snackbar.make(view, R.string.quickprivacy_disabled_message, Snackbar.LENGTH_INDEFINITE) snackbar.setAction(R.string.close) { onDismiss() } snackbar.addCallback(object : BaseTransientBottomBar.BaseCallback<Snackbar>() { override fun onDismissed(transientBottomBar: Snackbar?, event: Int) { super.onDismissed(transientBottomBar, event) if (event == DISMISS_EVENT_SWIPE) onDismiss() } }) return snackbar }
app/src/main/java/foundation/e/privacycentralapp/data/repositories/LocalStateRepository.kt +8 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import foundation.e.privacycentralapp.domain.entities.InternetPrivacyMode import foundation.e.privacycentralapp.domain.entities.LocationMode import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow class LocalStateRepository(context: Context) { companion object { Loading Loading @@ -84,6 +85,13 @@ class LocalStateRepository(context: Context) { val internetPrivacyMode: MutableStateFlow<InternetPrivacyMode> = MutableStateFlow(InternetPrivacyMode.REAL_IP) private val _showQuickPrivacyDisabledMessage = MutableStateFlow(false) val showQuickPrivacyDisabledMessage: StateFlow<Boolean> = _showQuickPrivacyDisabledMessage fun setShowQuickPrivacyDisabledMessage(show: Boolean) { _showQuickPrivacyDisabledMessage.value = show } var firstBoot: Boolean get() = sharedPref.getBoolean(KEY_FIRST_BOOT, true) set(value) = set(KEY_FIRST_BOOT, value) Loading
app/src/main/java/foundation/e/privacycentralapp/domain/usecases/FakeLocationStateUseCase.kt +31 −28 Original line number Diff line number Diff line Loading @@ -33,6 +33,7 @@ import foundation.e.privacymodules.permissions.data.AppOpModes 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.collect import kotlinx.coroutines.launch import kotlin.random.Random Loading @@ -46,8 +47,8 @@ class FakeLocationStateUseCase( private val appContext: Context, private val coroutineScope: CoroutineScope ) { // private val _locationMode = MutableStateFlow(LocationMode.REAL_LOCATION) // val locationMode: StateFlow<LocationMode> = _locationMode private val _configuredLocationMode = MutableStateFlow<Triple<LocationMode, Float?, Float?>>(Triple(LocationMode.REAL_LOCATION, null, null)) val configuredLocationMode: StateFlow<Triple<LocationMode, Float?, Float?>> = _configuredLocationMode init { coroutineScope.launch { Loading @@ -60,44 +61,23 @@ class FakeLocationStateUseCase( private val locationManager: LocationManager get() = appContext.getSystemService(Context.LOCATION_SERVICE) as LocationManager fun getLocationMode(): Triple<LocationMode, Float?, Float?> { val fakeLocation = localStateRepository.fakeLocation return if (fakeLocation != null && localStateRepository.locationMode.value == LocationMode.SPECIFIC_LOCATION) { Triple( LocationMode.SPECIFIC_LOCATION, fakeLocation.first, fakeLocation.second ) } else { Triple(localStateRepository.locationMode.value, null, null) } } private fun acquireLocationPermission() { permissionsModule.toggleDangerousPermission( appDesc, android.Manifest.permission.ACCESS_FINE_LOCATION, true ) // permissionsModule.setAppOpMode( // appDesc, AppOpsManager.OPSTR_COARSE_LOCATION, // AppOpModes.ALLOWED // ) // permissionsModule.setAppOpMode( // appDesc, AppOpsManager.OPSTR_FINE_LOCATION, // AppOpModes.ALLOWED // ) } private fun applySettings(isQuickPrivacyEnabled: Boolean, fakeLocation: Pair<Float, Float>?) { _configuredLocationMode.value = computeLocationMode(fakeLocation) if (isQuickPrivacyEnabled && fakeLocation != null) { if (permissionsModule.getAppOpMode(appDesc, AppOpsManager.OPSTR_MOCK_LOCATION) != AppOpModes.ALLOWED) { permissionsModule.setAppOpMode(appDesc, AppOpsManager.OPSTR_MOCK_LOCATION, AppOpModes.ALLOWED) } fakeLocationModule.startFakeLocation() fakeLocationModule.setFakeLocation(fakeLocation.first.toDouble(), fakeLocation.second.toDouble()) localStateRepository.locationMode.value = if (fakeLocation in citiesRepository.citiesLocationsList) LocationMode.RANDOM_LOCATION else LocationMode.SPECIFIC_LOCATION localStateRepository.locationMode.value = configuredLocationMode.value.first } else { fakeLocationModule.stopFakeLocation() localStateRepository.locationMode.value = LocationMode.REAL_LOCATION Loading @@ -105,10 +85,18 @@ class FakeLocationStateUseCase( } fun setSpecificLocation(latitude: Float, longitude: Float) { if (!localStateRepository.isQuickPrivacyEnabled) { localStateRepository.setShowQuickPrivacyDisabledMessage(true) } setFakeLocation(latitude to longitude) } fun setRandomLocation() { if (!localStateRepository.isQuickPrivacyEnabled) { localStateRepository.setShowQuickPrivacyDisabledMessage(true) } val randomIndex = Random.nextInt(citiesRepository.citiesLocationsList.size) val location = citiesRepository.citiesLocationsList[randomIndex] Loading @@ -117,12 +105,27 @@ class FakeLocationStateUseCase( private fun setFakeLocation(location: Pair<Float, Float>) { localStateRepository.fakeLocation = location applySettings(true, location) applySettings(localStateRepository.isQuickPrivacyEnabled, location) } fun stopFakeLocation() { if (!localStateRepository.isQuickPrivacyEnabled) { localStateRepository.setShowQuickPrivacyDisabledMessage(true) } localStateRepository.fakeLocation = null applySettings(true, null) applySettings(localStateRepository.isQuickPrivacyEnabled, null) } private fun computeLocationMode(fakeLocation: Pair<Float, Float>?): Triple<LocationMode, Float?, Float?> { return Triple( when { fakeLocation == null -> LocationMode.REAL_LOCATION fakeLocation in citiesRepository.citiesLocationsList -> LocationMode.RANDOM_LOCATION else -> LocationMode.SPECIFIC_LOCATION }, fakeLocation?.first, fakeLocation?.second ) } val currentLocation = MutableStateFlow<Location?>(null) Loading
app/src/main/java/foundation/e/privacycentralapp/domain/usecases/GetQuickPrivacyStateUseCase.kt +22 −2 Original line number Diff line number Diff line Loading @@ -21,12 +21,26 @@ import foundation.e.privacycentralapp.data.repositories.LocalStateRepository import foundation.e.privacycentralapp.domain.entities.InternetPrivacyMode import foundation.e.privacycentralapp.domain.entities.LocationMode import foundation.e.privacycentralapp.domain.entities.QuickPrivacyState import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.combine import kotlinx.coroutines.launch class GetQuickPrivacyStateUseCase( private val localStateRepository: LocalStateRepository, private val coroutineScope: CoroutineScope ) { init { coroutineScope.launch { localStateRepository.quickPrivacyEnabledFlow.collect { if (it) resetQuickPrivacyDisabledMessage() } } } class GetQuickPrivacyStateUseCase(private val localStateRepository: LocalStateRepository) { val quickPrivacyEnabledFlow = localStateRepository.quickPrivacyEnabledFlow val isQuickPrivacyEnabled get() = localStateRepository.isQuickPrivacyEnabled val quickPrivacyState = combine( localStateRepository.quickPrivacyEnabledFlow, Loading Loading @@ -77,4 +91,10 @@ class GetQuickPrivacyStateUseCase(private val localStateRepository: LocalStateRe val newState = !localStateRepository.isQuickPrivacyEnabled return localStateRepository.setQuickPrivacyReturnIsFirstActivation(newState) } val showQuickPrivacyDisabledMessage: StateFlow<Boolean> = localStateRepository.showQuickPrivacyDisabledMessage fun resetQuickPrivacyDisabledMessage() { localStateRepository.setShowQuickPrivacyDisabledMessage(false) } }