Loading app/build.gradle +3 −3 Original line number Diff line number Diff line Loading @@ -95,14 +95,14 @@ dependencies { compileOnly files('libs/e-ui-sdk-1.0.1-q.jar') implementation files('libs/lineage-sdk.jar') implementation files('libs/trackerfilter.aar') //implementation project(":privacymodulesapi") // include the google specific version of the modules, just for the google flavor googleImplementation project(":privacymodulesgoogle") //googleImplementation project(":privacymodulesgoogle") // include the e specific version of the modules, just for the e flavor eImplementation project(":privacymodulese") implementation 'foundation.e:privacymodule.api:0.4.1' implementation 'foundation.e:privacymodule.e-29:0.3.2' implementation 'foundation.e:privacymodule.tor:0.1.1' implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0' Loading app/src/main/java/foundation/e/privacycentralapp/DependencyContainer.kt +5 −3 Original line number Diff line number Diff line Loading @@ -94,18 +94,20 @@ class DependencyContainer constructor(val app: Application) { private val fakeLocationStateUseCase by lazy { FakeLocationStateUseCase( fakeLocationModule, permissionsModule, localStateRepository, CityDataSource, appDesc, GlobalScope) fakeLocationModule, permissionsModule, localStateRepository, CityDataSource, appDesc, context, GlobalScope ) } // ViewModelFactories val dashBoardViewModelFactory by lazy { DashBoardViewModelFactory(getQuickPrivacyStateUseCase, ipScramblingStateUseCase, trackersStatisticsUseCase, trackersStateUseCase) DashBoardViewModelFactory(getQuickPrivacyStateUseCase, ipScramblingStateUseCase, trackersStatisticsUseCase, trackersStateUseCase, fakeLocationStateUseCase) } val fakeLocationViewModelFactory by lazy { FakeLocationViewModelFactory( getQuickPrivacyStateUseCase = getQuickPrivacyStateUseCase, fakeLocationStateUseCase = fakeLocationStateUseCase) fakeLocationStateUseCase = fakeLocationStateUseCase ) } val blockerService = BlockerInterface.getInstance(context) Loading app/src/main/java/foundation/e/privacycentralapp/data/repositories/LocalStateRepository.kt +8 −5 Original line number Diff line number Diff line Loading @@ -44,10 +44,13 @@ class LocalStateRepository(context: Context) { var fakeLocation: Pair<Float, Float>? get() = if (sharedPref.contains(KEY_FAKE_LATITUDE) && sharedPref.contains( KEY_FAKE_LONGITUDE)) KEY_FAKE_LONGITUDE ) ) Pair( sharedPref.getFloat(KEY_FAKE_LATITUDE, 0f), sharedPref.getFloat(KEY_FAKE_LONGITUDE, 0f)) sharedPref.getFloat(KEY_FAKE_LONGITUDE, 0f) ) else null set(value) { if (value == null) { Loading app/src/main/java/foundation/e/privacycentralapp/domain/usecases/FakeLocationStateUseCase.kt +106 −17 Original line number Diff line number Diff line Loading @@ -18,6 +18,11 @@ package foundation.e.privacycentralapp.domain.usecases import android.app.AppOpsManager import android.content.Context import android.location.Location import android.location.LocationListener import android.location.LocationManager import android.util.Log import foundation.e.privacycentralapp.data.repositories.LocalStateRepository import foundation.e.privacycentralapp.domain.entities.LocationMode import foundation.e.privacycentralapp.dummy.CityDataSource Loading @@ -26,19 +31,23 @@ import foundation.e.privacymodules.permissions.PermissionsPrivacyModule 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 class FakeLocationStateUseCase( private val fakeLocationModule: IFakeLocationModule, private val permissionsModule: PermissionsPrivacyModule, private val localStateRepository: LocalStateRepository, private val citiesRepository: CityDataSource, private val appDesc: ApplicationDescription, private val appContext: Context, private val coroutineScope: CoroutineScope ) { private val _locationMode = MutableStateFlow(LocationMode.REAL_LOCATION) val locationMode: StateFlow<LocationMode> = _locationMode init { coroutineScope.launch { Loading @@ -48,15 +57,27 @@ class FakeLocationStateUseCase( } } fun getLocationMode(): LocationMode = when(localStateRepository.fakeLocation) { null -> LocationMode.REAL_LOCATION in citiesRepository.citiesLocationsList -> LocationMode.RANDOM_LOCATION else -> LocationMode.SPECIFIC_LOCATION 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 && _locationMode.value == LocationMode.SPECIFIC_LOCATION) { Triple( LocationMode.SPECIFIC_LOCATION, fakeLocation.first, fakeLocation.second ) } else { Triple(_locationMode.value, null, null) } } private fun acquireLocationPermission() { permissionsModule.toggleDangerousPermission(appDesc, android.Manifest.permission.ACCESS_FINE_LOCATION, true) permissionsModule.toggleDangerousPermission( appDesc, android.Manifest.permission.ACCESS_FINE_LOCATION, true ) // permissionsModule.setAppOpMode( // appDesc, AppOpsManager.OPSTR_COARSE_LOCATION, Loading @@ -74,10 +95,12 @@ class FakeLocationStateUseCase( permissionsModule.setAppOpMode(appDesc, AppOpsManager.OPSTR_MOCK_LOCATION, AppOpModes.ALLOWED) } fakeLocationModule.startFakeLocation() fakeLocationModule.setFakeLocation(fakeLocation.first.toDouble(), fakeLocation.second.toDouble()) _locationMode.value = if (fakeLocation in citiesRepository.citiesLocationsList) LocationMode.RANDOM_LOCATION else LocationMode.SPECIFIC_LOCATION } else { fakeLocationModule.stopFakeLocation() _locationMode.value = LocationMode.REAL_LOCATION } } Loading @@ -102,4 +125,70 @@ class FakeLocationStateUseCase( applySettings(true, null) } private var listener: LocationListener? = null val currentLocation = MutableStateFlow<Location?>(null) private var localListener = object : LocationListener { val providerName = LocationManager.NETWORK_PROVIDER override fun onLocationChanged(location: Location) { Log.e("DebugLoc", "onLocationChanged $location") currentLocation.value = location } override fun onProviderEnabled(provider: String?) { Log.e("DebugLoc", "ProvuderEnabled: $provider") reset(provider) } override fun onProviderDisabled(provider: String?) { Log.e("DebugLoc", "ProvuderDisabled: $provider") reset(provider) } private fun reset(provider: String?) { if (provider == providerName) { stopListeningLocation() currentLocation.value = null startListeningLocation() } } } fun startListeningLocation() { requestLocationUpdates(localListener) } fun stopListeningLocation() { removeUpdates(localListener) } fun requestLocationUpdates(listener: LocationListener) { acquireLocationPermission() try { Log.e("DebugLoc", "requestLocationUpdates") locationManager.requestLocationUpdates( LocationManager.NETWORK_PROVIDER, // TODO: tight this with fakelocation module. 0L, 0f, listener ) // 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) } } fun removeUpdates(listener: LocationListener) { locationManager.removeUpdates(listener) } } app/src/main/java/foundation/e/privacycentralapp/features/dashboard/DashboardFeature.kt +9 −2 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import foundation.e.flowmvi.SingleEventProducer import foundation.e.flowmvi.feature.BaseFeature import foundation.e.privacycentralapp.domain.entities.InternetPrivacyMode import foundation.e.privacycentralapp.domain.entities.LocationMode import foundation.e.privacycentralapp.domain.usecases.FakeLocationStateUseCase import foundation.e.privacycentralapp.domain.usecases.GetQuickPrivacyStateUseCase import foundation.e.privacycentralapp.domain.usecases.IpScramblingStateUseCase import foundation.e.privacycentralapp.domain.usecases.TrackersStateUseCase Loading Loading @@ -56,7 +57,7 @@ class DashboardFeature( val totalGraph: Int? = null, // val graphData val trackersCount: Int? = null, val activeTrackersCount: Int? = null, val dayTrackersCount: Int? = null, val dayStatistics: List<Int>? = null ) Loading Loading @@ -122,7 +123,8 @@ class DashboardFeature( getPrivacyStateUseCase: GetQuickPrivacyStateUseCase, ipScramblingStateUseCase: IpScramblingStateUseCase, trackersStatisticsUseCase: TrackersStatisticsUseCase, trackersStateUseCase: TrackersStateUseCase trackersStateUseCase: TrackersStateUseCase, fakeLocationStateUseCase: FakeLocationStateUseCase ): DashboardFeature = DashboardFeature( initialState = State(), Loading @@ -140,6 +142,8 @@ class DashboardFeature( is Effect.TrackersBlockedUpdatedEffect -> state.copy( isAllTrackersBlocked = effect.areAllTrackersBlocked ) is Effect.UpdateLocationModeEffect -> state.copy(locationMode = effect.mode) /*is Effect.OpenDashboardEffect -> State.DashboardState( effect.trackersCount, effect.activeTrackersCount, Loading Loading @@ -214,6 +218,9 @@ class DashboardFeature( }, trackersStateUseCase.areAllTrackersBlocked.map { Effect.TrackersBlockedUpdatedEffect(it) }, fakeLocationStateUseCase.locationMode.map { Effect.UpdateLocationModeEffect(it) } ) /* Loading Loading
app/build.gradle +3 −3 Original line number Diff line number Diff line Loading @@ -95,14 +95,14 @@ dependencies { compileOnly files('libs/e-ui-sdk-1.0.1-q.jar') implementation files('libs/lineage-sdk.jar') implementation files('libs/trackerfilter.aar') //implementation project(":privacymodulesapi") // include the google specific version of the modules, just for the google flavor googleImplementation project(":privacymodulesgoogle") //googleImplementation project(":privacymodulesgoogle") // include the e specific version of the modules, just for the e flavor eImplementation project(":privacymodulese") implementation 'foundation.e:privacymodule.api:0.4.1' implementation 'foundation.e:privacymodule.e-29:0.3.2' implementation 'foundation.e:privacymodule.tor:0.1.1' implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0' Loading
app/src/main/java/foundation/e/privacycentralapp/DependencyContainer.kt +5 −3 Original line number Diff line number Diff line Loading @@ -94,18 +94,20 @@ class DependencyContainer constructor(val app: Application) { private val fakeLocationStateUseCase by lazy { FakeLocationStateUseCase( fakeLocationModule, permissionsModule, localStateRepository, CityDataSource, appDesc, GlobalScope) fakeLocationModule, permissionsModule, localStateRepository, CityDataSource, appDesc, context, GlobalScope ) } // ViewModelFactories val dashBoardViewModelFactory by lazy { DashBoardViewModelFactory(getQuickPrivacyStateUseCase, ipScramblingStateUseCase, trackersStatisticsUseCase, trackersStateUseCase) DashBoardViewModelFactory(getQuickPrivacyStateUseCase, ipScramblingStateUseCase, trackersStatisticsUseCase, trackersStateUseCase, fakeLocationStateUseCase) } val fakeLocationViewModelFactory by lazy { FakeLocationViewModelFactory( getQuickPrivacyStateUseCase = getQuickPrivacyStateUseCase, fakeLocationStateUseCase = fakeLocationStateUseCase) fakeLocationStateUseCase = fakeLocationStateUseCase ) } val blockerService = BlockerInterface.getInstance(context) Loading
app/src/main/java/foundation/e/privacycentralapp/data/repositories/LocalStateRepository.kt +8 −5 Original line number Diff line number Diff line Loading @@ -44,10 +44,13 @@ class LocalStateRepository(context: Context) { var fakeLocation: Pair<Float, Float>? get() = if (sharedPref.contains(KEY_FAKE_LATITUDE) && sharedPref.contains( KEY_FAKE_LONGITUDE)) KEY_FAKE_LONGITUDE ) ) Pair( sharedPref.getFloat(KEY_FAKE_LATITUDE, 0f), sharedPref.getFloat(KEY_FAKE_LONGITUDE, 0f)) sharedPref.getFloat(KEY_FAKE_LONGITUDE, 0f) ) else null set(value) { if (value == null) { Loading
app/src/main/java/foundation/e/privacycentralapp/domain/usecases/FakeLocationStateUseCase.kt +106 −17 Original line number Diff line number Diff line Loading @@ -18,6 +18,11 @@ package foundation.e.privacycentralapp.domain.usecases import android.app.AppOpsManager import android.content.Context import android.location.Location import android.location.LocationListener import android.location.LocationManager import android.util.Log import foundation.e.privacycentralapp.data.repositories.LocalStateRepository import foundation.e.privacycentralapp.domain.entities.LocationMode import foundation.e.privacycentralapp.dummy.CityDataSource Loading @@ -26,19 +31,23 @@ import foundation.e.privacymodules.permissions.PermissionsPrivacyModule 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 class FakeLocationStateUseCase( private val fakeLocationModule: IFakeLocationModule, private val permissionsModule: PermissionsPrivacyModule, private val localStateRepository: LocalStateRepository, private val citiesRepository: CityDataSource, private val appDesc: ApplicationDescription, private val appContext: Context, private val coroutineScope: CoroutineScope ) { private val _locationMode = MutableStateFlow(LocationMode.REAL_LOCATION) val locationMode: StateFlow<LocationMode> = _locationMode init { coroutineScope.launch { Loading @@ -48,15 +57,27 @@ class FakeLocationStateUseCase( } } fun getLocationMode(): LocationMode = when(localStateRepository.fakeLocation) { null -> LocationMode.REAL_LOCATION in citiesRepository.citiesLocationsList -> LocationMode.RANDOM_LOCATION else -> LocationMode.SPECIFIC_LOCATION 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 && _locationMode.value == LocationMode.SPECIFIC_LOCATION) { Triple( LocationMode.SPECIFIC_LOCATION, fakeLocation.first, fakeLocation.second ) } else { Triple(_locationMode.value, null, null) } } private fun acquireLocationPermission() { permissionsModule.toggleDangerousPermission(appDesc, android.Manifest.permission.ACCESS_FINE_LOCATION, true) permissionsModule.toggleDangerousPermission( appDesc, android.Manifest.permission.ACCESS_FINE_LOCATION, true ) // permissionsModule.setAppOpMode( // appDesc, AppOpsManager.OPSTR_COARSE_LOCATION, Loading @@ -74,10 +95,12 @@ class FakeLocationStateUseCase( permissionsModule.setAppOpMode(appDesc, AppOpsManager.OPSTR_MOCK_LOCATION, AppOpModes.ALLOWED) } fakeLocationModule.startFakeLocation() fakeLocationModule.setFakeLocation(fakeLocation.first.toDouble(), fakeLocation.second.toDouble()) _locationMode.value = if (fakeLocation in citiesRepository.citiesLocationsList) LocationMode.RANDOM_LOCATION else LocationMode.SPECIFIC_LOCATION } else { fakeLocationModule.stopFakeLocation() _locationMode.value = LocationMode.REAL_LOCATION } } Loading @@ -102,4 +125,70 @@ class FakeLocationStateUseCase( applySettings(true, null) } private var listener: LocationListener? = null val currentLocation = MutableStateFlow<Location?>(null) private var localListener = object : LocationListener { val providerName = LocationManager.NETWORK_PROVIDER override fun onLocationChanged(location: Location) { Log.e("DebugLoc", "onLocationChanged $location") currentLocation.value = location } override fun onProviderEnabled(provider: String?) { Log.e("DebugLoc", "ProvuderEnabled: $provider") reset(provider) } override fun onProviderDisabled(provider: String?) { Log.e("DebugLoc", "ProvuderDisabled: $provider") reset(provider) } private fun reset(provider: String?) { if (provider == providerName) { stopListeningLocation() currentLocation.value = null startListeningLocation() } } } fun startListeningLocation() { requestLocationUpdates(localListener) } fun stopListeningLocation() { removeUpdates(localListener) } fun requestLocationUpdates(listener: LocationListener) { acquireLocationPermission() try { Log.e("DebugLoc", "requestLocationUpdates") locationManager.requestLocationUpdates( LocationManager.NETWORK_PROVIDER, // TODO: tight this with fakelocation module. 0L, 0f, listener ) // 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) } } fun removeUpdates(listener: LocationListener) { locationManager.removeUpdates(listener) } }
app/src/main/java/foundation/e/privacycentralapp/features/dashboard/DashboardFeature.kt +9 −2 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import foundation.e.flowmvi.SingleEventProducer import foundation.e.flowmvi.feature.BaseFeature import foundation.e.privacycentralapp.domain.entities.InternetPrivacyMode import foundation.e.privacycentralapp.domain.entities.LocationMode import foundation.e.privacycentralapp.domain.usecases.FakeLocationStateUseCase import foundation.e.privacycentralapp.domain.usecases.GetQuickPrivacyStateUseCase import foundation.e.privacycentralapp.domain.usecases.IpScramblingStateUseCase import foundation.e.privacycentralapp.domain.usecases.TrackersStateUseCase Loading Loading @@ -56,7 +57,7 @@ class DashboardFeature( val totalGraph: Int? = null, // val graphData val trackersCount: Int? = null, val activeTrackersCount: Int? = null, val dayTrackersCount: Int? = null, val dayStatistics: List<Int>? = null ) Loading Loading @@ -122,7 +123,8 @@ class DashboardFeature( getPrivacyStateUseCase: GetQuickPrivacyStateUseCase, ipScramblingStateUseCase: IpScramblingStateUseCase, trackersStatisticsUseCase: TrackersStatisticsUseCase, trackersStateUseCase: TrackersStateUseCase trackersStateUseCase: TrackersStateUseCase, fakeLocationStateUseCase: FakeLocationStateUseCase ): DashboardFeature = DashboardFeature( initialState = State(), Loading @@ -140,6 +142,8 @@ class DashboardFeature( is Effect.TrackersBlockedUpdatedEffect -> state.copy( isAllTrackersBlocked = effect.areAllTrackersBlocked ) is Effect.UpdateLocationModeEffect -> state.copy(locationMode = effect.mode) /*is Effect.OpenDashboardEffect -> State.DashboardState( effect.trackersCount, effect.activeTrackersCount, Loading Loading @@ -214,6 +218,9 @@ class DashboardFeature( }, trackersStateUseCase.areAllTrackersBlocked.map { Effect.TrackersBlockedUpdatedEffect(it) }, fakeLocationStateUseCase.locationMode.map { Effect.UpdateLocationModeEffect(it) } ) /* Loading