From 3f2adc24d18c4396b0f9954a2fe267808c7d410a Mon Sep 17 00:00:00 2001 From: jacquarg Date: Tue, 13 Aug 2024 22:28:18 +0200 Subject: [PATCH 1/8] feat:2396: Whitelist app for fake location UI and ContentProvider --- app/src/main/AndroidManifest.xml | 11 +- .../e/advancedprivacy/KoinModule.kt | 17 +- .../repositories/LocalStateRepositoryImpl.kt | 16 +- .../usecases/FakeLocationForAppUseCase.kt | 47 ++++++ .../usecases/FakeLocationStateUseCase.kt | 158 ++++-------------- .../domain/usecases/ListenLocationUseCase.kt | 122 ++++++++++++++ .../FakeLocationContentProvider.kt | 78 +++++++++ .../features/location/FakeLocationFragment.kt | 33 +++- .../features/location/FakeLocationState.kt | 7 +- .../location/FakeLocationViewModel.kt | 29 +++- .../res/layout/fragment_fake_location.xml | 27 +++ ...tem_app_toggle.xml => item_app_toggle.xml} | 2 - app/src/main/res/values/strings.xml | 4 + .../data/repositories/AppListsRepository.kt | 4 +- .../repositories/LocalStateRepository.kt | 5 +- 15 files changed, 410 insertions(+), 150 deletions(-) create mode 100644 app/src/main/java/foundation/e/advancedprivacy/domain/usecases/FakeLocationForAppUseCase.kt create mode 100644 app/src/main/java/foundation/e/advancedprivacy/domain/usecases/ListenLocationUseCase.kt create mode 100644 app/src/main/java/foundation/e/advancedprivacy/externalinterfaces/contentproviders/FakeLocationContentProvider.kt rename app/src/main/res/layout/{ipscrambling_item_app_toggle.xml => item_app_toggle.xml} (94%) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6be3dbc0..b9ccdb6f 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -45,6 +45,14 @@ android:windowSoftInputMode="adjustResize" tools:replace="android:icon,android:label,android:theme" > + + + - - \ No newline at end of file + diff --git a/app/src/main/java/foundation/e/advancedprivacy/KoinModule.kt b/app/src/main/java/foundation/e/advancedprivacy/KoinModule.kt index 7503646f..5d426a36 100644 --- a/app/src/main/java/foundation/e/advancedprivacy/KoinModule.kt +++ b/app/src/main/java/foundation/e/advancedprivacy/KoinModule.kt @@ -29,9 +29,11 @@ import foundation.e.advancedprivacy.domain.entities.DisplayableApp import foundation.e.advancedprivacy.domain.entities.ProfileType import foundation.e.advancedprivacy.domain.repositories.LocalStateRepository import foundation.e.advancedprivacy.domain.usecases.AppTrackersUseCase +import foundation.e.advancedprivacy.domain.usecases.FakeLocationForAppUseCase import foundation.e.advancedprivacy.domain.usecases.FakeLocationStateUseCase import foundation.e.advancedprivacy.domain.usecases.GetQuickPrivacyStateUseCase import foundation.e.advancedprivacy.domain.usecases.IpScramblingStateUseCase +import foundation.e.advancedprivacy.domain.usecases.ListenLocationUseCase import foundation.e.advancedprivacy.domain.usecases.ShowFeaturesWarningUseCase import foundation.e.advancedprivacy.domain.usecases.TrackerDetailsUseCase import foundation.e.advancedprivacy.domain.usecases.TrackersAndAppsListsUseCase @@ -40,7 +42,6 @@ import foundation.e.advancedprivacy.domain.usecases.TrackersStateUseCase import foundation.e.advancedprivacy.domain.usecases.TrackersStatisticsUseCase import foundation.e.advancedprivacy.dummy.CityDataSource import foundation.e.advancedprivacy.externalinterfaces.permissions.IPermissionsPrivacyModule -import foundation.e.advancedprivacy.fakelocation.fakelocationModule import foundation.e.advancedprivacy.features.dashboard.DashboardViewModel import foundation.e.advancedprivacy.features.internetprivacy.InternetPrivacyViewModel import foundation.e.advancedprivacy.features.location.FakeLocationViewModel @@ -68,7 +69,7 @@ import org.koin.dsl.module import timber.log.Timber val appModule = module { - includes(coreModule, trackersModule, fakelocationModule, ipScramblerModule, trackerServiceModule) + includes(coreModule, trackersModule, ipScramblerModule, trackerServiceModule) single { CoroutineScope( @@ -113,18 +114,18 @@ val appModule = module { single { CityDataSource } single { ResourcesRepository(androidContext()) } + singleOf(::FakeLocationStateUseCase) + single { - FakeLocationStateUseCase( - fakeLocationModule = get(), + ListenLocationUseCase( permissionsModule = get(), - localStateRepository = get(), - citiesRepository = get(), appDesc = get(named("AdvancedPrivacy")), - appContext = androidContext(), - coroutineScope = get() + appContext = androidContext() ) } + singleOf(::FakeLocationForAppUseCase) + singleOf(::GetQuickPrivacyStateUseCase) single { IpScramblingStateUseCase( diff --git a/app/src/main/java/foundation/e/advancedprivacy/data/repositories/LocalStateRepositoryImpl.kt b/app/src/main/java/foundation/e/advancedprivacy/data/repositories/LocalStateRepositoryImpl.kt index 4bd5f203..144aebbd 100644 --- a/app/src/main/java/foundation/e/advancedprivacy/data/repositories/LocalStateRepositoryImpl.kt +++ b/app/src/main/java/foundation/e/advancedprivacy/data/repositories/LocalStateRepositoryImpl.kt @@ -19,9 +19,9 @@ package foundation.e.advancedprivacy.data.repositories import android.content.Context +import androidx.core.content.edit import foundation.e.advancedprivacy.domain.entities.ApplicationDescription import foundation.e.advancedprivacy.domain.entities.FeatureState -import foundation.e.advancedprivacy.domain.entities.LocationMode import foundation.e.advancedprivacy.domain.entities.MainFeatures import foundation.e.advancedprivacy.domain.repositories.LocalStateRepository import kotlinx.coroutines.flow.MutableSharedFlow @@ -38,6 +38,7 @@ class LocalStateRepositoryImpl(context: Context) : LocalStateRepository { private const val KEY_FAKE_LOCATION = "fakeLocation" private const val KEY_FAKE_LATITUDE = "fakeLatitude" private const val KEY_FAKE_LONGITUDE = "fakeLongitude" + private const val KEY_FAKE_LOCATION_WHITELIST = "fakeLocationWhitelist" private const val KEY_FIRST_BOOT = "firstBoot" private const val KEY_HIDE_WARNING_TRACKERS = "hide_warning_trackers" private const val KEY_HIDE_WARNING_LOCATION = "hide_warning_location" @@ -81,7 +82,18 @@ class LocalStateRepositoryImpl(context: Context) : LocalStateRepository { .apply() } - override val locationMode: MutableStateFlow = MutableStateFlow(LocationMode.REAL_LOCATION) + private val _fakeLocationWhitelistedApps = + MutableStateFlow>(sharedPref.getStringSet(KEY_FAKE_LOCATION_WHITELIST, emptySet()) ?: emptySet()) + override val fakeLocationWhitelistedApps = _fakeLocationWhitelistedApps.asStateFlow() + + override suspend fun updateFakeLocationWhitelist(whitelist: Set) { + _fakeLocationWhitelistedApps.update { + sharedPref.edit(commit = true) { + putStringSet(KEY_FAKE_LOCATION_WHITELIST, whitelist) + } + whitelist + } + } private val _ipScramblingSetting = MutableStateFlow(sharedPref.getBoolean(KEY_IP_SCRAMBLING, false)) diff --git a/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/FakeLocationForAppUseCase.kt b/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/FakeLocationForAppUseCase.kt new file mode 100644 index 00000000..daa87be7 --- /dev/null +++ b/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/FakeLocationForAppUseCase.kt @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2024 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 . + */ +package foundation.e.advancedprivacy.domain.usecases + +import foundation.e.advancedprivacy.data.repositories.AppListsRepository +import foundation.e.advancedprivacy.domain.repositories.LocalStateRepository + +class FakeLocationForAppUseCase( + private val appListsRepository: AppListsRepository, + private val localStateRepository: LocalStateRepository +) { + + fun getFakeLocationOrNull(packageName: String, uid: Int): Pair? { + if (!localStateRepository.fakeLocationEnabled.value || + ( + packageName in setOf( + AppListsRepository.PNAME_MICROG_SERVICES_CORE, + AppListsRepository.PNAME_FUSED_LOCATION, + AppListsRepository.PNAME_ANDROID_SYSTEM + ) + ) + ) { + return null + } + + val app = appListsRepository.getApp(uid) + return if (app?.apId != null && app.apId in localStateRepository.fakeLocationWhitelistedApps.value) { + null + } else { + localStateRepository.fakeLocation + } + } +} 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 6c948020..2abc8e4f 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 @@ -1,6 +1,6 @@ /* * Copyright (C) 2023 MURENA SAS - * Copyright (C) 2021 E FOUNDATION + * Copyright (C) 2021 - 2024 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 @@ -18,41 +18,30 @@ package foundation.e.advancedprivacy.domain.usecases -import android.app.AppOpsManager -import android.content.Context -import android.content.pm.PackageManager -import android.location.Location -import android.location.LocationListener -import android.location.LocationManager -import android.os.Bundle -import foundation.e.advancedprivacy.domain.entities.AppOpModes -import foundation.e.advancedprivacy.domain.entities.ApplicationDescription +import foundation.e.advancedprivacy.data.repositories.AppListsRepository +import foundation.e.advancedprivacy.domain.entities.DisplayableApp import foundation.e.advancedprivacy.domain.entities.LocationMode +import foundation.e.advancedprivacy.domain.entities.ToggleableApp 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 kotlin.random.Random import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.update +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch -import timber.log.Timber class FakeLocationStateUseCase( - private val fakeLocationModule: FakeLocationModule, - private val permissionsModule: IPermissionsPrivacyModule, private val localStateRepository: LocalStateRepository, private val citiesRepository: CityDataSource, - private val appDesc: ApplicationDescription, - private val appContext: Context, + private val appListsRepository: AppListsRepository, coroutineScope: CoroutineScope ) { private val _configuredLocationMode = MutableStateFlow>( Triple(LocationMode.REAL_LOCATION, null, null) ) - val configuredLocationMode: StateFlow> = _configuredLocationMode init { @@ -63,30 +52,15 @@ class FakeLocationStateUseCase( } } - private val locationManager: LocationManager - get() = appContext.getSystemService(Context.LOCATION_SERVICE) as LocationManager - - private fun hasAcquireLocationPermission(): Boolean { - return (appContext.checkSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) || - permissionsModule.toggleDangerousPermission(appDesc, android.Manifest.permission.ACCESS_FINE_LOCATION, true) - } - private fun applySettings(isEnabled: Boolean, fakeLocation: Pair, isSpecificLocation: Boolean = false) { - _configuredLocationMode.value = computeLocationMode(isEnabled, fakeLocation, isSpecificLocation) - - if (isEnabled && hasAcquireMockLocationPermission()) { - fakeLocationModule.startFakeLocation() - fakeLocationModule.setFakeLocation(fakeLocation.first.toDouble(), fakeLocation.second.toDouble()) - localStateRepository.locationMode.value = configuredLocationMode.value.first - } else { - fakeLocationModule.stopFakeLocation() - localStateRepository.locationMode.value = LocationMode.REAL_LOCATION + val locationMode = when { + !isEnabled -> LocationMode.REAL_LOCATION + (fakeLocation in citiesRepository.citiesLocationsList && !isSpecificLocation) -> + LocationMode.RANDOM_LOCATION + else -> LocationMode.SPECIFIC_LOCATION } - } - private fun hasAcquireMockLocationPermission(): Boolean { - return (permissionsModule.getAppOpMode(appDesc, AppOpsManager.OPSTR_MOCK_LOCATION) == AppOpModes.ALLOWED) || - permissionsModule.setAppOpMode(appDesc, AppOpsManager.OPSTR_MOCK_LOCATION, AppOpModes.ALLOWED) + _configuredLocationMode.value = Triple(locationMode, fakeLocation.first, fakeLocation.second) } fun setSpecificLocation(latitude: Float, longitude: Float) { @@ -111,99 +85,35 @@ class FakeLocationStateUseCase( applySettings(false, localStateRepository.fakeLocation) } - private fun computeLocationMode( - isFakeLocationEnabled: Boolean, - fakeLocation: Pair, - isSpecificLocation: Boolean = false - ): Triple { - return Triple( - when { - !isFakeLocationEnabled -> LocationMode.REAL_LOCATION - (fakeLocation in citiesRepository.citiesLocationsList && !isSpecificLocation) -> - LocationMode.RANDOM_LOCATION - else -> LocationMode.SPECIFIC_LOCATION - }, - fakeLocation.first, - fakeLocation.second - ) - } - - val currentLocation = MutableStateFlow(null) - - private var localListener = object : LocationListener { - - override fun onLocationChanged(location: Location) { - currentLocation.update { location } - } - - @Deprecated("Deprecated since API 29, never called.") - override fun onStatusChanged(provider: String?, status: Int, extras: Bundle?) {} + suspend fun toggleBlacklist(app: DisplayableApp) { + val whitelist = localStateRepository.fakeLocationWhitelistedApps.value.toMutableSet() + val apIds = app.apps.map { it.apId }.toSet() - override fun onProviderEnabled(provider: String) { - reset() - } - - override fun onProviderDisabled(provider: String) { - reset() - } - - private fun reset() { - stopListeningLocation() - currentLocation.value = null - startListeningLocation() - } - } - - fun startListeningLocation(): Boolean { - return if (hasAcquireLocationPermission()) { - requestLocationUpdates() - true + if (apIds.any { whitelist.contains(it) }) { + whitelist.removeAll(apIds) } else { - false + whitelist.addAll(apIds) } + + localStateRepository.updateFakeLocationWhitelist(whitelist) } - fun stopListeningLocation() { - locationManager.removeUpdates(localListener) + suspend fun resetBlacklist() { + localStateRepository.updateFakeLocationWhitelist(emptySet()) } - private fun requestLocationUpdates() { - val networkProvider = LocationManager.NETWORK_PROVIDER - .takeIf { it in locationManager.allProviders } - val gpsProvider = LocationManager.GPS_PROVIDER - .takeIf { it in locationManager.allProviders } - - try { - networkProvider?.let { - locationManager.requestLocationUpdates( - it, - 1000L, - 0f, - localListener - ) - } - gpsProvider?.let { - locationManager.requestLocationUpdates( - it, - 1000L, - 0f, - localListener - ) - } + fun canResetBlacklist(): Flow = localStateRepository.fakeLocationWhitelistedApps.map { it.isNotEmpty() } - var lastKnownLocation = networkProvider?.let { - locationManager.getLastKnownLocation(it) - } - - if (lastKnownLocation == null) { - lastKnownLocation = gpsProvider?.let { - locationManager.getLastKnownLocation(it) - } + fun appsWithBlacklist(): Flow> { + return combine( + appListsRepository.displayableApps.map { apps -> + apps.filter { it.hasLocationPermission }.sortedBy { it.label.toString() } + }, + localStateRepository.fakeLocationWhitelistedApps + ) { apps, whitelist -> + apps.map { app -> + ToggleableApp(app = app, isOn = !app.apps.any { whitelist.contains(it.apId) }) } - - lastKnownLocation?.let { localListener.onLocationChanged(it) } - } catch (se: SecurityException) { - Timber.e(se, "Missing permission") } } } diff --git a/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/ListenLocationUseCase.kt b/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/ListenLocationUseCase.kt new file mode 100644 index 00000000..e636c4eb --- /dev/null +++ b/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/ListenLocationUseCase.kt @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2024 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 . + */ +package foundation.e.advancedprivacy.domain.usecases + +import android.content.Context +import android.content.pm.PackageManager +import android.location.Location +import android.location.LocationListener +import android.location.LocationManager +import android.os.Bundle +import foundation.e.advancedprivacy.domain.entities.ApplicationDescription +import foundation.e.advancedprivacy.externalinterfaces.permissions.IPermissionsPrivacyModule +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.update +import timber.log.Timber + +class ListenLocationUseCase( + private val permissionsModule: IPermissionsPrivacyModule, + private val appContext: Context, + private val appDesc: ApplicationDescription +) { + private val locationManager: LocationManager + get() = appContext.getSystemService(Context.LOCATION_SERVICE) as LocationManager + + private fun hasAcquireLocationPermission(): Boolean { + return (appContext.checkSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) || + permissionsModule.toggleDangerousPermission(appDesc, android.Manifest.permission.ACCESS_FINE_LOCATION, true) + } + + val currentLocation = MutableStateFlow(null) + + private var localListener = object : LocationListener { + + override fun onLocationChanged(location: Location) { + currentLocation.update { location } + } + + @Deprecated("Deprecated since API 29, never called.") + override fun onStatusChanged(provider: String?, status: Int, extras: Bundle?) {} + + override fun onProviderEnabled(provider: String) { + reset() + } + + override fun onProviderDisabled(provider: String) { + reset() + } + + private fun reset() { + stopListeningLocation() + currentLocation.value = null + startListeningLocation() + } + } + + fun startListeningLocation(): Boolean { + return if (hasAcquireLocationPermission()) { + requestLocationUpdates() + true + } else { + false + } + } + + fun stopListeningLocation() { + locationManager.removeUpdates(localListener) + } + + private fun requestLocationUpdates() { + val networkProvider = LocationManager.NETWORK_PROVIDER + .takeIf { it in locationManager.allProviders } + val gpsProvider = LocationManager.GPS_PROVIDER + .takeIf { it in locationManager.allProviders } + + try { + networkProvider?.let { + locationManager.requestLocationUpdates( + it, + 1000L, + 0f, + localListener + ) + } + gpsProvider?.let { + locationManager.requestLocationUpdates( + it, + 1000L, + 0f, + localListener + ) + } + + var lastKnownLocation = networkProvider?.let { + locationManager.getLastKnownLocation(it) + } + + if (lastKnownLocation == null) { + lastKnownLocation = gpsProvider?.let { + locationManager.getLastKnownLocation(it) + } + } + + lastKnownLocation?.let { localListener.onLocationChanged(it) } + } catch (se: SecurityException) { + Timber.e(se, "Missing permission") + } + } +} diff --git a/app/src/main/java/foundation/e/advancedprivacy/externalinterfaces/contentproviders/FakeLocationContentProvider.kt b/app/src/main/java/foundation/e/advancedprivacy/externalinterfaces/contentproviders/FakeLocationContentProvider.kt new file mode 100644 index 00000000..de7bc328 --- /dev/null +++ b/app/src/main/java/foundation/e/advancedprivacy/externalinterfaces/contentproviders/FakeLocationContentProvider.kt @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2024 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 . + */ +package foundation.e.advancedprivacy.externalinterfaces.contentproviders + +import android.content.ContentProvider +import android.content.ContentValues +import android.database.Cursor +import android.net.Uri +import android.os.Bundle +import foundation.e.advancedprivacy.domain.usecases.FakeLocationForAppUseCase +import org.koin.android.ext.android.inject + +class FakeLocationContentProvider : ContentProvider() { + private val PARAM_UID = "uid" + private val PARAM_LATITUDE = "latitude" + private val PARAM_LONGITUDE = "longitude" + + private val fakeLocationForAppUseCase: FakeLocationForAppUseCase by inject() + + override fun call(method: String, arg: String?, extras: Bundle?): Bundle? { + val appUid = extras?.getInt(PARAM_UID, -1) ?: -1 + + return fakeLocationForAppUseCase.getFakeLocationOrNull(arg!!, appUid)?.let { (lat, lon) -> + Bundle().apply { + putDouble(PARAM_LATITUDE, lat.toDouble()) + putDouble(PARAM_LONGITUDE, lon.toDouble()) + } + } + } + + override fun onCreate(): Boolean { + return true + } + + override fun query( + uri: Uri, + projection: Array?, + selection: String?, + selectionArgs: Array?, + sortOrder: String? + ): Cursor? { + // Use call instead + return null + } + + override fun getType(uri: Uri): String? { + return "text/plain" + } + + override fun insert(p0: Uri, p1: ContentValues?): Uri? { + // ReadOnly content provider + return null + } + + override fun delete(p0: Uri, p1: String?, p2: Array?): Int { + // ReadOnly content provider + return 0 + } + + override fun update(p0: Uri, p1: ContentValues?, p2: String?, p3: Array?): Int { + // ReadOnly content provider + return 0 + } +} 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 79912d8e..f2181908 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 @@ -1,6 +1,6 @@ /* * Copyright (C) 2023 MURENA SAS - * Copyright (C) 2021 E FOUNDATION + * Copyright (C) 2021 - 2024 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 @@ -34,6 +34,7 @@ import androidx.core.widget.addTextChangedListener import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle +import androidx.recyclerview.widget.LinearLayoutManager import com.google.android.material.textfield.TextInputLayout import com.google.android.material.textfield.TextInputLayout.END_ICON_CUSTOM import com.google.android.material.textfield.TextInputLayout.END_ICON_NONE @@ -51,8 +52,10 @@ import com.mapbox.mapboxsdk.maps.MapboxMap import com.mapbox.mapboxsdk.maps.Style import foundation.e.advancedprivacy.R import foundation.e.advancedprivacy.common.NavToolbarFragment +import foundation.e.advancedprivacy.common.setToolTipForAsterisk import foundation.e.advancedprivacy.databinding.FragmentFakeLocationBinding import foundation.e.advancedprivacy.domain.entities.LocationMode +import foundation.e.advancedprivacy.features.internetprivacy.ToggleAppsAdapter import foundation.e.advancedprivacy.features.location.FakeLocationViewModel.Action import kotlinx.coroutines.Job import kotlinx.coroutines.delay @@ -122,6 +125,20 @@ class FakeLocationFragment : NavToolbarFragment(R.layout.fragment_fake_location) } } + binding.apps.apply { + layoutManager = LinearLayoutManager(requireContext()) + setHasFixedSize(true) + adapter = ToggleAppsAdapter(R.layout.item_app_toggle) { app -> + viewModel.onToggleApp(app) + } + } + + setToolTipForAsterisk( + textView = binding.targetedAppsSubtitles, + textId = R.string.ipscrambling_select_app, + tooltipTextId = R.string.location_app_list_infos + ) + startListening() } @@ -296,6 +313,10 @@ class FakeLocationFragment : NavToolbarFragment(R.layout.fragment_fake_location) binding.edittextLongitude.addTextChangedListener(afterTextChanged = ::onLonTextChanged) binding.edittextLatitude.onFocusChangeListener = latLonOnFocusChangeListener binding.edittextLongitude.onFocusChangeListener = latLonOnFocusChangeListener + + binding.btnReset.setOnClickListener { + viewModel.onClickResetAllApplications() + } } @SuppressLint("MissingPermission") @@ -331,6 +352,16 @@ class FakeLocationFragment : NavToolbarFragment(R.layout.fragment_fake_location) binding.edittextLatitude.setText(state.specificLatitude?.toString()) binding.edittextLongitude.setText(state.specificLongitude?.toString()) } + + binding.apps.post { + (binding.apps.adapter as ToggleAppsAdapter?)?.setData( + list = state.appsWithBlackList, + isEnabled = state.mode != LocationMode.REAL_LOCATION + ) + } + + binding.btnReset.isVisible = state.showResetBlacklist + binding.btnReset.isClickable = state.showResetBlacklist } @SuppressLint("MissingPermission") 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 ec2eef18..364fe417 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 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 E FOUNDATION + * Copyright (C) 2022 - 2024 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 @@ -19,11 +19,14 @@ package foundation.e.advancedprivacy.features.location import android.location.Location import foundation.e.advancedprivacy.domain.entities.LocationMode +import foundation.e.advancedprivacy.domain.entities.ToggleableApp data class FakeLocationState( val mode: LocationMode = LocationMode.REAL_LOCATION, val currentLocation: Location? = null, val specificLatitude: Float? = null, val specificLongitude: Float? = null, - val forceRefresh: Boolean = false + val forceRefresh: Boolean = false, + val appsWithBlackList: List = emptyList(), + val showResetBlacklist: 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 9962037f..af5c1a35 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 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 E FOUNDATION + * Copyright (C) 2021, 2024 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 @@ -20,7 +20,9 @@ package foundation.e.advancedprivacy.features.location import android.location.Location import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import foundation.e.advancedprivacy.domain.entities.DisplayableApp import foundation.e.advancedprivacy.domain.usecases.FakeLocationStateUseCase +import foundation.e.advancedprivacy.domain.usecases.ListenLocationUseCase import kotlin.time.Duration.Companion.milliseconds import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.FlowPreview @@ -37,7 +39,8 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.withContext class FakeLocationViewModel( - private val fakeLocationStateUseCase: FakeLocationStateUseCase + private val fakeLocationStateUseCase: FakeLocationStateUseCase, + private val listenLocationUseCase: ListenLocationUseCase ) : ViewModel() { companion object { private val SET_SPECIFIC_LOCATION_DELAY = 200.milliseconds @@ -46,7 +49,7 @@ class FakeLocationViewModel( private val _state = MutableStateFlow(FakeLocationState()) val state = _state.asStateFlow() - val currentLocation: StateFlow = fakeLocationStateUseCase.currentLocation + val currentLocation: StateFlow = listenLocationUseCase.currentLocation private val _singleEvents = MutableSharedFlow() val singleEvents = _singleEvents.asSharedFlow() @@ -69,7 +72,13 @@ class FakeLocationViewModel( specificLocationInputFlow .debounce(SET_SPECIFIC_LOCATION_DELAY).map { action -> fakeLocationStateUseCase.setSpecificLocation(action.latitude, action.longitude) - } + }, + fakeLocationStateUseCase.appsWithBlacklist().map { apps -> + _state.update { s -> s.copy(appsWithBlackList = apps) } + }, + fakeLocationStateUseCase.canResetBlacklist().map { + _state.update { s -> s.copy(showResetBlacklist = it) } + } ).collect {} } } @@ -77,7 +86,7 @@ class FakeLocationViewModel( fun submitAction(action: Action) = viewModelScope.launch { when (action) { is Action.StartListeningLocation -> actionStartListeningLocation() - is Action.StopListeningLocation -> fakeLocationStateUseCase.stopListeningLocation() + is Action.StopListeningLocation -> listenLocationUseCase.stopListeningLocation() is Action.SetSpecificLocationAction -> setSpecificLocation(action) is Action.UseRandomLocationAction -> fakeLocationStateUseCase.setRandomLocation() is Action.UseRealLocationAction -> @@ -86,7 +95,7 @@ class FakeLocationViewModel( } private suspend fun actionStartListeningLocation() { - val started = fakeLocationStateUseCase.startListeningLocation() + val started = listenLocationUseCase.startListeningLocation() if (!started) { _singleEvents.emit(SingleEvent.RequestLocationPermission) } @@ -96,6 +105,14 @@ class FakeLocationViewModel( specificLocationInputFlow.emit(action) } + fun onToggleApp(app: DisplayableApp) = viewModelScope.launch(Dispatchers.IO) { + fakeLocationStateUseCase.toggleBlacklist(app) + } + + fun onClickResetAllApplications() = viewModelScope.launch(Dispatchers.IO) { + fakeLocationStateUseCase.resetBlacklist() + } + sealed class SingleEvent { object RequestLocationPermission : SingleEvent() data class ErrorEvent(val error: String) : SingleEvent() diff --git a/app/src/main/res/layout/fragment_fake_location.xml b/app/src/main/res/layout/fragment_fake_location.xml index 5da95e12..4309f13d 100644 --- a/app/src/main/res/layout/fragment_fake_location.xml +++ b/app/src/main/res/layout/fragment_fake_location.xml @@ -157,7 +157,34 @@ /> + + + + diff --git a/app/src/main/res/layout/ipscrambling_item_app_toggle.xml b/app/src/main/res/layout/item_app_toggle.xml similarity index 94% rename from app/src/main/res/layout/ipscrambling_item_app_toggle.xml rename to app/src/main/res/layout/item_app_toggle.xml index 1fbffa06..62d7ded8 100644 --- a/app/src/main/res/layout/ipscrambling_item_app_toggle.xml +++ b/app/src/main/res/layout/item_app_toggle.xml @@ -5,8 +5,6 @@ android:id="@+id/container" android:layout_height="52dp" android:layout_width="match_parent" - android:paddingStart="16dp" - android:paddingEnd="16dp" android:gravity="center_vertical" > diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index bbf4744e..f7728bd7 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -105,6 +105,10 @@ Latitude Invalid coordinates + Only apps with location permission are listed. + Reset applications + + Manage apps\' trackers Trackers are pieces of code hidden in apps. They collect your data and follow your activity 24/7. See below all app tracking activity in your device. diff --git a/core/src/main/java/foundation/e/advancedprivacy/data/repositories/AppListsRepository.kt b/core/src/main/java/foundation/e/advancedprivacy/data/repositories/AppListsRepository.kt index 448a10af..aa16f3e4 100644 --- a/core/src/main/java/foundation/e/advancedprivacy/data/repositories/AppListsRepository.kt +++ b/core/src/main/java/foundation/e/advancedprivacy/data/repositories/AppListsRepository.kt @@ -50,7 +50,9 @@ class AppListsRepository( private const val PNAME_SETTINGS = "com.android.settings" private const val PNAME_PWAPLAYER = "foundation.e.pwaplayer" private const val PNAME_INTENT_VERIFICATION = "com.android.statementservice" - private const val PNAME_MICROG_SERVICES_CORE = "com.google.android.gms" + const val PNAME_MICROG_SERVICES_CORE = "com.google.android.gms" + const val PNAME_FUSED_LOCATION = "com.android.location.fused" + const val PNAME_ANDROID_SYSTEM = "android" private val compatibilityInternetPNames = setOf( PNAME_PWAPLAYER, diff --git a/core/src/main/java/foundation/e/advancedprivacy/domain/repositories/LocalStateRepository.kt b/core/src/main/java/foundation/e/advancedprivacy/domain/repositories/LocalStateRepository.kt index 39212a23..9826155e 100644 --- a/core/src/main/java/foundation/e/advancedprivacy/domain/repositories/LocalStateRepository.kt +++ b/core/src/main/java/foundation/e/advancedprivacy/domain/repositories/LocalStateRepository.kt @@ -18,7 +18,6 @@ package foundation.e.advancedprivacy.domain.repositories import foundation.e.advancedprivacy.domain.entities.ApplicationDescription import foundation.e.advancedprivacy.domain.entities.FeatureState -import foundation.e.advancedprivacy.domain.entities.LocationMode import foundation.e.advancedprivacy.domain.entities.MainFeatures import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharedFlow @@ -35,7 +34,9 @@ interface LocalStateRepository { var fakeLocation: Pair - val locationMode: MutableStateFlow + val fakeLocationWhitelistedApps: StateFlow> + + suspend fun updateFakeLocationWhitelist(whitelist: Set) fun setIpScramblingSetting(enabled: Boolean) val ipScramblingSetting: StateFlow -- GitLab From 3004b1ce320787df3b978be3101e852a01249f5c Mon Sep 17 00:00:00 2001 From: jacquarg Date: Tue, 13 Aug 2024 22:32:01 +0200 Subject: [PATCH 2/8] feat:2396: Use FeatureMode for Tracker and Fakelocation feature state --- README.md | 22 +++++------------ .../e/advancedprivacy/Notifications.kt | 9 ++++--- .../{TrackerMode.kt => FeatureMode.kt} | 4 ++-- .../usecases/GetQuickPrivacyStateUseCase.kt | 23 +++++++++++------- .../features/dashboard/DashboardFragment.kt | 24 +++++++++---------- .../features/dashboard/DashboardState.kt | 6 ++--- .../features/dashboard/DashboardViewModel.kt | 4 ++-- .../InternetPrivacyFragment.kt | 2 +- .../apptrackers/AppTrackersViewModel.kt | 4 ++-- .../trackerdetails/TrackerDetailsViewModel.kt | 4 ++-- .../e/advancedprivacy/widget/Widget.kt | 8 +++---- .../e/advancedprivacy/widget/WidgetUI.kt | 13 +++++----- .../fragment_internet_activity_policy.xml | 7 ------ 13 files changed, 61 insertions(+), 69 deletions(-) rename app/src/main/java/foundation/e/advancedprivacy/domain/entities/{TrackerMode.kt => FeatureMode.kt} (91%) diff --git a/README.md b/README.md index 3a30d873..92e3a9c4 100644 --- a/README.md +++ b/README.md @@ -66,22 +66,11 @@ To strictly enforce the code quality, this project has a pre-commit hook which i ## Build dependencies -TrackerFilter won't work unless your rom was build with this specific netd project: +Trackers filter and Fake location won't work unless your rom was build with this specific netd project, android framework base and microG. -[android_system_netd](../../../e_privacycentral_android_system_netd) +Custom netd project communicate to AdvancedPrivay through a Unix socket, to log and block name resolution. -To create an /e/ build with this specific project, follow the documentation to create an usual /e/ build for your device https://doc.e.foundation/devices until `repo sync` - -After `repo sync` all the sources, replace -``` -system/netd -``` - -with this repo [android_system_netd](../../../e_privacycentral_android_system_netd) - -then run the build as usual - -This won't include advanced privacy, you still need to build the app. +Custom android framework base and microG will consult the foundation.e.advancedprivacy.fakelocations ContentProvider for fake location instruction. ## Build If you'd like to build AdvancedPrivacy locally, you should be able to just clone and build with no issues. @@ -90,7 +79,7 @@ For building from CLI, you can execute use `./gradlew assemble = combine( + val trackerMode: Flow = combine( localStateRepository.blockTrackers, localStateRepository.areAllTrackersBlocked ) { isBlockTrackers, isAllTrackersBlocked -> when { - isBlockTrackers && isAllTrackersBlocked -> TrackerMode.DENIED - isBlockTrackers && !isAllTrackersBlocked -> TrackerMode.CUSTOM - else -> TrackerMode.VULNERABLE + isBlockTrackers && isAllTrackersBlocked -> FeatureMode.DENIED + isBlockTrackers && !isAllTrackersBlocked -> FeatureMode.CUSTOM + else -> FeatureMode.VULNERABLE } } - val isLocationHidden: Flow = localStateRepository.locationMode.map { locationMode -> - locationMode != LocationMode.REAL_LOCATION + val locationMode: Flow = combine( + localStateRepository.fakeLocationEnabled, + localStateRepository.fakeLocationWhitelistedApps + ) { enabled, whitelist -> + when { + !enabled -> FeatureMode.VULNERABLE + whitelist.isEmpty() -> FeatureMode.DENIED + else -> FeatureMode.CUSTOM + } } val ipScramblingMode: Flow = diff --git a/app/src/main/java/foundation/e/advancedprivacy/features/dashboard/DashboardFragment.kt b/app/src/main/java/foundation/e/advancedprivacy/features/dashboard/DashboardFragment.kt index a8c17ec5..099d8fbb 100644 --- a/app/src/main/java/foundation/e/advancedprivacy/features/dashboard/DashboardFragment.kt +++ b/app/src/main/java/foundation/e/advancedprivacy/features/dashboard/DashboardFragment.kt @@ -33,8 +33,8 @@ import foundation.e.advancedprivacy.R import foundation.e.advancedprivacy.common.BigNumberFormatter import foundation.e.advancedprivacy.common.NavToolbarFragment import foundation.e.advancedprivacy.databinding.FragmentDashboardBinding +import foundation.e.advancedprivacy.domain.entities.FeatureMode import foundation.e.advancedprivacy.domain.entities.FeatureState -import foundation.e.advancedprivacy.domain.entities.TrackerMode import foundation.e.advancedprivacy.features.dashboard.DashboardViewModel.SingleEvent import foundation.e.advancedprivacy.features.trackers.TrackerTab import kotlinx.coroutines.launch @@ -192,29 +192,29 @@ class DashboardFragment : NavToolbarFragment(R.layout.fragment_dashboard) { binding.dataApps.number.text = state.appsWithCallsCount.toString() with(binding.trackersControl) { - switchFeature.isChecked = state.trackerMode != TrackerMode.VULNERABLE + switchFeature.isChecked = state.trackerMode != FeatureMode.VULNERABLE stateLabel.setText( when (state.trackerMode) { - TrackerMode.DENIED -> R.string.dashboard_state_trackers_on - TrackerMode.VULNERABLE -> R.string.dashboard_state_trackers_off - TrackerMode.CUSTOM -> R.string.dashboard_state_trackers_custom + FeatureMode.DENIED -> R.string.dashboard_state_trackers_on + FeatureMode.VULNERABLE -> R.string.dashboard_state_trackers_off + FeatureMode.CUSTOM -> R.string.dashboard_state_trackers_custom } ) - stateLabel.setTextColor(getStateColor(state.trackerMode != TrackerMode.VULNERABLE)) + stateLabel.setTextColor(getStateColor(state.trackerMode != FeatureMode.VULNERABLE)) } with(binding.fakeLocation) { - switchFeature.isChecked = state.isLocationHidden + switchFeature.isChecked = state.locationMode != FeatureMode.VULNERABLE stateLabel.setText( - if (state.isLocationHidden) { - R.string.dashboard_state_geolocation_on - } else { - R.string.dashboard_state_geolocation_off + when (state.locationMode) { + FeatureMode.DENIED -> R.string.dashboard_state_geolocation_on + FeatureMode.VULNERABLE -> R.string.dashboard_state_geolocation_off + FeatureMode.CUSTOM -> R.string.dashboard_state_trackers_custom } ) - stateLabel.setTextColor(getStateColor(state.isLocationHidden)) + stateLabel.setTextColor(getStateColor(state.locationMode != FeatureMode.VULNERABLE)) } with(binding.ipScrambling) { diff --git a/app/src/main/java/foundation/e/advancedprivacy/features/dashboard/DashboardState.kt b/app/src/main/java/foundation/e/advancedprivacy/features/dashboard/DashboardState.kt index e53c8879..4afdc84f 100644 --- a/app/src/main/java/foundation/e/advancedprivacy/features/dashboard/DashboardState.kt +++ b/app/src/main/java/foundation/e/advancedprivacy/features/dashboard/DashboardState.kt @@ -19,13 +19,13 @@ package foundation.e.advancedprivacy.features.dashboard import foundation.e.advancedprivacy.domain.entities.AppWithCount +import foundation.e.advancedprivacy.domain.entities.FeatureMode import foundation.e.advancedprivacy.domain.entities.FeatureState -import foundation.e.advancedprivacy.domain.entities.TrackerMode import foundation.e.advancedprivacy.domain.entities.TrackerWithCount data class DashboardState( - val trackerMode: TrackerMode = TrackerMode.VULNERABLE, - val isLocationHidden: Boolean = false, + val trackerMode: FeatureMode = FeatureMode.VULNERABLE, + val locationMode: FeatureMode = FeatureMode.VULNERABLE, val ipScramblingMode: FeatureState = FeatureState.STOPPING, val blockedCallsCount: Int = 0, val appsWithCallsCount: Int = 0, diff --git a/app/src/main/java/foundation/e/advancedprivacy/features/dashboard/DashboardViewModel.kt b/app/src/main/java/foundation/e/advancedprivacy/features/dashboard/DashboardViewModel.kt index e9835e87..72c616d5 100644 --- a/app/src/main/java/foundation/e/advancedprivacy/features/dashboard/DashboardViewModel.kt +++ b/app/src/main/java/foundation/e/advancedprivacy/features/dashboard/DashboardViewModel.kt @@ -75,8 +75,8 @@ class DashboardViewModel( getPrivacyStateUseCase.trackerMode.map { _state.update { s -> s.copy(trackerMode = it) } }, - getPrivacyStateUseCase.isLocationHidden.map { - _state.update { s -> s.copy(isLocationHidden = it) } + getPrivacyStateUseCase.locationMode.map { + _state.update { s -> s.copy(locationMode = it) } }, getPrivacyStateUseCase.otherVpnRunning.map { _singleEvents.emit( diff --git a/app/src/main/java/foundation/e/advancedprivacy/features/internetprivacy/InternetPrivacyFragment.kt b/app/src/main/java/foundation/e/advancedprivacy/features/internetprivacy/InternetPrivacyFragment.kt index ec4fe5ee..f9f57006 100644 --- a/app/src/main/java/foundation/e/advancedprivacy/features/internetprivacy/InternetPrivacyFragment.kt +++ b/app/src/main/java/foundation/e/advancedprivacy/features/internetprivacy/InternetPrivacyFragment.kt @@ -55,7 +55,7 @@ class InternetPrivacyFragment : NavToolbarFragment(R.layout.fragment_internet_ac binding.apps.apply { layoutManager = LinearLayoutManager(requireContext()) setHasFixedSize(true) - adapter = ToggleAppsAdapter(R.layout.ipscrambling_item_app_toggle) { app -> + adapter = ToggleAppsAdapter(R.layout.item_app_toggle) { app -> viewModel.onClickToggleAppIpScrambled(app) } } diff --git a/app/src/main/java/foundation/e/advancedprivacy/features/trackers/apptrackers/AppTrackersViewModel.kt b/app/src/main/java/foundation/e/advancedprivacy/features/trackers/apptrackers/AppTrackersViewModel.kt index 726be53c..87b12e38 100644 --- a/app/src/main/java/foundation/e/advancedprivacy/features/trackers/apptrackers/AppTrackersViewModel.kt +++ b/app/src/main/java/foundation/e/advancedprivacy/features/trackers/apptrackers/AppTrackersViewModel.kt @@ -23,7 +23,7 @@ import androidx.annotation.StringRes import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import foundation.e.advancedprivacy.domain.entities.DisplayableApp -import foundation.e.advancedprivacy.domain.entities.TrackerMode +import foundation.e.advancedprivacy.domain.entities.FeatureMode import foundation.e.advancedprivacy.domain.usecases.AppTrackersUseCase import foundation.e.advancedprivacy.domain.usecases.GetQuickPrivacyStateUseCase import foundation.e.advancedprivacy.domain.usecases.TrackersStateUseCase @@ -65,7 +65,7 @@ class AppTrackersViewModel( suspend fun doOnStartedState() = withContext(Dispatchers.IO) { merge( getQuickPrivacyStateUseCase.trackerMode.map { - _state.update { s -> s.copy(isTrackersBlockingEnabled = it != TrackerMode.VULNERABLE) } + _state.update { s -> s.copy(isTrackersBlockingEnabled = it != FeatureMode.VULNERABLE) } }, trackersStatisticsUseCase.listenUpdates().map { fetchStatistics() } ).collect { } diff --git a/app/src/main/java/foundation/e/advancedprivacy/features/trackers/trackerdetails/TrackerDetailsViewModel.kt b/app/src/main/java/foundation/e/advancedprivacy/features/trackers/trackerdetails/TrackerDetailsViewModel.kt index a5b2bbdf..259869b5 100644 --- a/app/src/main/java/foundation/e/advancedprivacy/features/trackers/trackerdetails/TrackerDetailsViewModel.kt +++ b/app/src/main/java/foundation/e/advancedprivacy/features/trackers/trackerdetails/TrackerDetailsViewModel.kt @@ -23,7 +23,7 @@ import androidx.annotation.StringRes import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import foundation.e.advancedprivacy.domain.entities.DisplayableApp -import foundation.e.advancedprivacy.domain.entities.TrackerMode +import foundation.e.advancedprivacy.domain.entities.FeatureMode import foundation.e.advancedprivacy.domain.usecases.GetQuickPrivacyStateUseCase import foundation.e.advancedprivacy.domain.usecases.TrackerDetailsUseCase import foundation.e.advancedprivacy.domain.usecases.TrackersStateUseCase @@ -57,7 +57,7 @@ class TrackerDetailsViewModel( suspend fun doOnStartedState() = withContext(Dispatchers.IO) { merge( getQuickPrivacyStateUseCase.trackerMode.map { - _state.update { s -> s.copy(isTrackersBlockingEnabled = it != TrackerMode.VULNERABLE) } + _state.update { s -> s.copy(isTrackersBlockingEnabled = it != FeatureMode.VULNERABLE) } }, trackersStatisticsUseCase.listenUpdates().map { fetchStatistics() } ).collect { } diff --git a/app/src/main/java/foundation/e/advancedprivacy/widget/Widget.kt b/app/src/main/java/foundation/e/advancedprivacy/widget/Widget.kt index cc989ff6..e9ed94f6 100644 --- a/app/src/main/java/foundation/e/advancedprivacy/widget/Widget.kt +++ b/app/src/main/java/foundation/e/advancedprivacy/widget/Widget.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 E FOUNDATION + * Copyright (C) 2022 - 2024 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 @@ -81,12 +81,12 @@ class Widget : AppWidgetProvider() { ): StateFlow { return combine( getPrivacyStateUseCase.trackerMode, - getPrivacyStateUseCase.isLocationHidden, + getPrivacyStateUseCase.locationMode, getPrivacyStateUseCase.ipScramblingMode - ) { trackerMode, isLocationHidden, ipScramblingMode -> + ) { trackerMode, locationMode, ipScramblingMode -> State( trackerMode = trackerMode, - isLocationHidden = isLocationHidden, + locationMode = locationMode, ipScramblingMode = ipScramblingMode ) }.sample(50) diff --git a/app/src/main/java/foundation/e/advancedprivacy/widget/WidgetUI.kt b/app/src/main/java/foundation/e/advancedprivacy/widget/WidgetUI.kt index 1d685506..f07277fa 100644 --- a/app/src/main/java/foundation/e/advancedprivacy/widget/WidgetUI.kt +++ b/app/src/main/java/foundation/e/advancedprivacy/widget/WidgetUI.kt @@ -37,8 +37,8 @@ import foundation.e.advancedprivacy.R import foundation.e.advancedprivacy.Widget import foundation.e.advancedprivacy.Widget.Companion.isDarkText import foundation.e.advancedprivacy.common.BigNumberFormatter +import foundation.e.advancedprivacy.domain.entities.FeatureMode import foundation.e.advancedprivacy.domain.entities.FeatureState -import foundation.e.advancedprivacy.domain.entities.TrackerMode import foundation.e.advancedprivacy.main.MainActivity import foundation.e.advancedprivacy.widget.WidgetCommandReceiver.Companion.ACTION_TOGGLE_IPSCRAMBLING import foundation.e.advancedprivacy.widget.WidgetCommandReceiver.Companion.ACTION_TOGGLE_LOCATION @@ -46,8 +46,8 @@ import foundation.e.advancedprivacy.widget.WidgetCommandReceiver.Companion.ACTIO import foundation.e.advancedprivacy.widget.WidgetCommandReceiver.Companion.PARAM_FEATURE_ENABLED data class State( - val trackerMode: TrackerMode = TrackerMode.VULNERABLE, - val isLocationHidden: Boolean = false, + val trackerMode: FeatureMode = FeatureMode.VULNERABLE, + val locationMode: FeatureMode = FeatureMode.VULNERABLE, val ipScramblingMode: FeatureState = FeatureState.STOPPING, val blockedCallsCount: Int = 0, val appsWithCallsCount: Int = 0 @@ -103,7 +103,7 @@ fun render(context: Context, state: State, appWidgetManager: AppWidgetManager, w ) ) - val trackersEnabled = state.trackerMode != TrackerMode.VULNERABLE + val trackersEnabled = state.trackerMode != FeatureMode.VULNERABLE setSwitchState(views, R.id.toggle_trackers, trackersEnabled) @@ -120,7 +120,8 @@ fun render(context: Context, state: State, appWidgetManager: AppWidgetManager, w ) ) - setSwitchState(views, R.id.toggle_location, state.isLocationHidden) + val locationEnabled = state.locationMode != FeatureMode.VULNERABLE + setSwitchState(views, R.id.toggle_location, locationEnabled) setOnClickPendingIntent( R.id.fake_location, @@ -129,7 +130,7 @@ fun render(context: Context, state: State, appWidgetManager: AppWidgetManager, w REQUEST_CODE_TOGGLE_LOCATION, Intent(context, WidgetCommandReceiver::class.java).apply { action = ACTION_TOGGLE_LOCATION - putExtra(PARAM_FEATURE_ENABLED, !state.isLocationHidden) + putExtra(PARAM_FEATURE_ENABLED, !locationEnabled) }, FLAG_IMMUTABLE or FLAG_UPDATE_CURRENT ) diff --git a/app/src/main/res/layout/fragment_internet_activity_policy.xml b/app/src/main/res/layout/fragment_internet_activity_policy.xml index ee82abf8..12b51fbb 100644 --- a/app/src/main/res/layout/fragment_internet_activity_policy.xml +++ b/app/src/main/res/layout/fragment_internet_activity_policy.xml @@ -20,14 +20,8 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" - > - - - Date: Tue, 13 Aug 2024 22:32:24 +0200 Subject: [PATCH 3/8] feat:2396: Remove deprecated fakelocation through mock location module --- app/build.gradle | 2 - fakelocation/.gitignore | 1 - fakelocation/build.gradle | 57 -------- fakelocation/consumer-rules.pro | 0 fakelocation/proguard-rules.pro | 21 --- fakelocation/src/main/AndroidManifest.xml | 31 ---- .../fakelocation/KoinModule.kt | 26 ---- .../domain/usecases/FakeLocationModule.kt | 133 ------------------ .../services/FakeLocationService.kt | 110 --------------- settings.gradle | 1 - 10 files changed, 382 deletions(-) delete mode 100644 fakelocation/.gitignore delete mode 100644 fakelocation/build.gradle delete mode 100644 fakelocation/consumer-rules.pro delete mode 100644 fakelocation/proguard-rules.pro delete mode 100644 fakelocation/src/main/AndroidManifest.xml delete mode 100644 fakelocation/src/main/java/foundation/e/advancedprivacy/fakelocation/KoinModule.kt delete mode 100644 fakelocation/src/main/java/foundation/e/advancedprivacy/fakelocation/domain/usecases/FakeLocationModule.kt delete mode 100644 fakelocation/src/main/java/foundation/e/advancedprivacy/fakelocation/services/FakeLocationService.kt diff --git a/app/build.gradle b/app/build.gradle index 67a3afa6..fe8c3ce1 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -142,8 +142,6 @@ dependencies { standaloneImplementation project(':permissionsstandalone') eosImplementation project(':permissionseos') - implementation project(':fakelocation') - eosImplementation files('libs/lineage-sdk.jar') implementation project(':trackers') diff --git a/fakelocation/.gitignore b/fakelocation/.gitignore deleted file mode 100644 index 42afabfd..00000000 --- a/fakelocation/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build \ No newline at end of file diff --git a/fakelocation/build.gradle b/fakelocation/build.gradle deleted file mode 100644 index 2563939c..00000000 --- a/fakelocation/build.gradle +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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 . - */ - -plugins { - id 'com.android.library' - id 'org.jetbrains.kotlin.android' -} - -android { - compileSdkVersion buildConfig.compileSdk - - defaultConfig { - minSdkVersion buildConfig.minSdk - targetSdkVersion buildConfig.targetSdk - - consumerProguardFiles "consumer-rules.pro" - } - - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' - } - } - compileOptions { - sourceCompatibility JavaVersion.VERSION_17 - targetCompatibility JavaVersion.VERSION_17 - } - kotlinOptions { - jvmTarget = '17' - } - namespace 'foundation.e.privacymodules.fakelocation' -} - -dependencies { - implementation( - libs.bundles.koin, - libs.bundles.kotlin.android.coroutines - ) - implementation project(':core') - - -} diff --git a/fakelocation/consumer-rules.pro b/fakelocation/consumer-rules.pro deleted file mode 100644 index e69de29b..00000000 diff --git a/fakelocation/proguard-rules.pro b/fakelocation/proguard-rules.pro deleted file mode 100644 index 481bb434..00000000 --- a/fakelocation/proguard-rules.pro +++ /dev/null @@ -1,21 +0,0 @@ -# Add project specific ProGuard rules here. -# You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/fakelocation/src/main/AndroidManifest.xml b/fakelocation/src/main/AndroidManifest.xml deleted file mode 100644 index 623a180d..00000000 --- a/fakelocation/src/main/AndroidManifest.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/fakelocation/src/main/java/foundation/e/advancedprivacy/fakelocation/KoinModule.kt b/fakelocation/src/main/java/foundation/e/advancedprivacy/fakelocation/KoinModule.kt deleted file mode 100644 index 9512875b..00000000 --- a/fakelocation/src/main/java/foundation/e/advancedprivacy/fakelocation/KoinModule.kt +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2023 MURENA SAS - * - * 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 . - */ - -package foundation.e.advancedprivacy.fakelocation - -import foundation.e.advancedprivacy.fakelocation.domain.usecases.FakeLocationModule -import org.koin.core.module.dsl.singleOf -import org.koin.dsl.module - -val fakelocationModule = module { - singleOf(::FakeLocationModule) -} diff --git a/fakelocation/src/main/java/foundation/e/advancedprivacy/fakelocation/domain/usecases/FakeLocationModule.kt b/fakelocation/src/main/java/foundation/e/advancedprivacy/fakelocation/domain/usecases/FakeLocationModule.kt deleted file mode 100644 index c9aac0a5..00000000 --- a/fakelocation/src/main/java/foundation/e/advancedprivacy/fakelocation/domain/usecases/FakeLocationModule.kt +++ /dev/null @@ -1,133 +0,0 @@ -/* - * 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 . - */ - -package foundation.e.advancedprivacy.fakelocation.domain.usecases - -import android.content.Context -import android.content.Context.LOCATION_SERVICE -import android.location.Location -import android.location.LocationManager -import android.location.LocationManager.GPS_PROVIDER -import android.location.LocationManager.NETWORK_PROVIDER -import android.location.provider.ProviderProperties -import android.os.Build -import android.os.SystemClock -import android.util.Log -import foundation.e.advancedprivacy.fakelocation.services.FakeLocationService - -/** - * Implementation of the functionality of fake location. - * All of them are available for normal application, so just one version is enough. - * - * @param context an Android context, to retrieve system services for example. - */ -class FakeLocationModule(private val context: Context) { - companion object { - private const val TAG = "FakeLocationModule" - } - - /** - * Handy accessor to the locationManager service. - * We avoid getting it on module initialization to wait for the context to be ready. - */ - private val locationManager: LocationManager get() = - context.getSystemService(LOCATION_SERVICE) as LocationManager - - /** - * List of all the Location provider that will be mocked. - */ - private val providers = locationManager.allProviders - .intersect(listOf(GPS_PROVIDER, NETWORK_PROVIDER)) - - /** - * @see IFakeLocationModule.startFakeLocation - */ - @Synchronized - fun startFakeLocation() { - providers.forEach { provider -> - try { - locationManager.removeTestProvider(provider) - } catch (e: Exception) { - Log.w(TAG, "Test provider $provider already removed.") - } - - locationManager.addTestProvider( - provider, - false, - false, - false, - false, - false, - true, - true, - ProviderProperties.POWER_USAGE_LOW, - ProviderProperties.ACCURACY_FINE - ) - try { - locationManager.setTestProviderEnabled(provider, true) - } catch (e: Exception) { - Log.e(TAG, "Can't enable test $provider", e) - } - } - } - - fun setFakeLocation(latitude: Double, longitude: Double) { - context.startService(FakeLocationService.buildFakeLocationIntent(context, latitude, longitude)) - } - - internal fun setTestProviderLocation(latitude: Double, longitude: Double) { - providers.forEach { provider -> - val location = Location(provider) - location.latitude = latitude - location.longitude = longitude - - // Set default value for all the other required fields. - location.altitude = 3.0 - location.time = System.currentTimeMillis() - location.speed = 0.01f - location.bearing = 1f - location.accuracy = 3f - location.elapsedRealtimeNanos = SystemClock.elapsedRealtimeNanos() - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - location.bearingAccuracyDegrees = 0.1f - location.verticalAccuracyMeters = 0.1f - location.speedAccuracyMetersPerSecond = 0.01f - } - try { - locationManager.setTestProviderLocation(provider, location) - } catch (e: Exception) { - Log.e(TAG, "Can't set location for test provider $provider", e) - } - } - } - - /** - * @see IFakeLocationModule.stopFakeLocation - */ - fun stopFakeLocation() { - context.stopService(FakeLocationService.buildStopIntent(context)) - providers.forEach { provider -> - try { - locationManager.setTestProviderEnabled(provider, false) - locationManager.removeTestProvider(provider) - } catch (e: Exception) { - Log.d(TAG, "Test provider $provider already removed.") - } - } - } -} diff --git a/fakelocation/src/main/java/foundation/e/advancedprivacy/fakelocation/services/FakeLocationService.kt b/fakelocation/src/main/java/foundation/e/advancedprivacy/fakelocation/services/FakeLocationService.kt deleted file mode 100644 index f431b05c..00000000 --- a/fakelocation/src/main/java/foundation/e/advancedprivacy/fakelocation/services/FakeLocationService.kt +++ /dev/null @@ -1,110 +0,0 @@ -/* - * 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 . - */ - -package foundation.e.advancedprivacy.fakelocation.services - -import android.app.Service -import android.content.Context -import android.content.Intent -import android.os.CountDownTimer -import android.os.IBinder -import android.util.Log -import foundation.e.advancedprivacy.fakelocation.domain.usecases.FakeLocationModule - -class FakeLocationService : Service() { - - enum class Actions { - START_FAKE_LOCATION - } - - companion object { - private const val PERIOD_LOCATION_UPDATE = 1000L - private const val PERIOD_UPDATES_SERIE = 2 * 60 * 1000L - - private const val PARAM_LATITUDE = "PARAM_LATITUDE" - private const val PARAM_LONGITUDE = "PARAM_LONGITUDE" - - fun buildFakeLocationIntent(context: Context, latitude: Double, longitude: Double): Intent { - return Intent(context, FakeLocationService::class.java).apply { - action = Actions.START_FAKE_LOCATION.name - putExtra(PARAM_LATITUDE, latitude) - putExtra(PARAM_LONGITUDE, longitude) - } - } - - fun buildStopIntent(context: Context) = Intent(context, FakeLocationService::class.java) - } - - private lateinit var fakeLocationModule: FakeLocationModule - - private var countDownTimer: CountDownTimer? = null - - private var fakeLocation: Pair? = null - - override fun onCreate() { - super.onCreate() - fakeLocationModule = FakeLocationModule(applicationContext) - } - - override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { - intent?.let { - when (it.action?.let { str -> Actions.valueOf(str) }) { - Actions.START_FAKE_LOCATION -> { - fakeLocation = Pair( - it.getDoubleExtra(PARAM_LATITUDE, 0.0), - it.getDoubleExtra(PARAM_LONGITUDE, 0.0) - ) - initTimer() - } - else -> {} - } - } - - return START_STICKY - } - - override fun onDestroy() { - countDownTimer?.cancel() - super.onDestroy() - } - - private fun initTimer() { - countDownTimer?.cancel() - countDownTimer = object : CountDownTimer(PERIOD_UPDATES_SERIE, PERIOD_LOCATION_UPDATE) { - override fun onTick(millisUntilFinished: Long) { - fakeLocation?.let { - try { - fakeLocationModule.setTestProviderLocation( - it.first, - it.second - ) - } catch (e: Exception) { - Log.d("FakeLocationService", "setting fake location", e) - } - } - } - - override fun onFinish() { - initTimer() - } - }.start() - } - - override fun onBind(intent: Intent?): IBinder? { - return null - } -} diff --git a/settings.gradle b/settings.gradle index 6468ff66..0c00702e 100644 --- a/settings.gradle +++ b/settings.gradle @@ -8,7 +8,6 @@ pluginManagement { include ':app' rootProject.name = "AdvancedPrivacy" -include ':fakelocation' include ':core' include ':permissionsstandalone' include ':trackers' -- GitLab From 74fb6291728cc792dd6932e69cc1093590c0c2b4 Mon Sep 17 00:00:00 2001 From: jacquarg Date: Mon, 19 Aug 2024 17:48:18 +0200 Subject: [PATCH 4/8] feat:2396: MR fixes. --- README.md | 4 +-- .../repositories/LocalStateRepositoryImpl.kt | 4 +-- .../usecases/FakeLocationForAppUseCase.kt | 18 ++++++------- .../usecases/FakeLocationStateUseCase.kt | 7 ++--- .../domain/usecases/ListenLocationUseCase.kt | 27 ++++++++++--------- .../FakeLocationContentProvider.kt | 2 +- 6 files changed, 32 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 92e3a9c4..521f91a7 100644 --- a/README.md +++ b/README.md @@ -66,9 +66,9 @@ To strictly enforce the code quality, this project has a pre-commit hook which i ## Build dependencies -Trackers filter and Fake location won't work unless your rom was build with this specific netd project, android framework base and microG. +Trackers filter and Fake location won't work unless your ROM was built with this specific netd project, android framework base and microG. -Custom netd project communicate to AdvancedPrivay through a Unix socket, to log and block name resolution. +Custom netd project communicates to AdvancedPrivacy through a Unix socket, to log and block name resolution. Custom android framework base and microG will consult the foundation.e.advancedprivacy.fakelocations ContentProvider for fake location instruction. diff --git a/app/src/main/java/foundation/e/advancedprivacy/data/repositories/LocalStateRepositoryImpl.kt b/app/src/main/java/foundation/e/advancedprivacy/data/repositories/LocalStateRepositoryImpl.kt index 144aebbd..6c1be351 100644 --- a/app/src/main/java/foundation/e/advancedprivacy/data/repositories/LocalStateRepositoryImpl.kt +++ b/app/src/main/java/foundation/e/advancedprivacy/data/repositories/LocalStateRepositoryImpl.kt @@ -82,8 +82,8 @@ class LocalStateRepositoryImpl(context: Context) : LocalStateRepository { .apply() } - private val _fakeLocationWhitelistedApps = - MutableStateFlow>(sharedPref.getStringSet(KEY_FAKE_LOCATION_WHITELIST, emptySet()) ?: emptySet()) + private val savedWhitelist = sharedPref.getStringSet(KEY_FAKE_LOCATION_WHITELIST, emptySet()) ?: emptySet() + private val _fakeLocationWhitelistedApps = MutableStateFlow>(savedWhitelist) override val fakeLocationWhitelistedApps = _fakeLocationWhitelistedApps.asStateFlow() override suspend fun updateFakeLocationWhitelist(whitelist: Set) { diff --git a/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/FakeLocationForAppUseCase.kt b/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/FakeLocationForAppUseCase.kt index daa87be7..d1b4ebee 100644 --- a/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/FakeLocationForAppUseCase.kt +++ b/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/FakeLocationForAppUseCase.kt @@ -24,16 +24,14 @@ class FakeLocationForAppUseCase( private val localStateRepository: LocalStateRepository ) { - fun getFakeLocationOrNull(packageName: String, uid: Int): Pair? { - if (!localStateRepository.fakeLocationEnabled.value || - ( - packageName in setOf( - AppListsRepository.PNAME_MICROG_SERVICES_CORE, - AppListsRepository.PNAME_FUSED_LOCATION, - AppListsRepository.PNAME_ANDROID_SYSTEM - ) - ) - ) { + private val nullFakeLocationPkgs = listOf( + AppListsRepository.PNAME_MICROG_SERVICES_CORE, + AppListsRepository.PNAME_FUSED_LOCATION, + AppListsRepository.PNAME_ANDROID_SYSTEM + ) + + fun getFakeLocationOrNull(packageName: String?, uid: Int): Pair? { + if (packageName == null || !localStateRepository.fakeLocationEnabled.value || packageName in nullFakeLocationPkgs) { return null } 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 2abc8e4f..5dd158c0 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 @@ -55,8 +55,7 @@ class FakeLocationStateUseCase( private fun applySettings(isEnabled: Boolean, fakeLocation: Pair, isSpecificLocation: Boolean = false) { val locationMode = when { !isEnabled -> LocationMode.REAL_LOCATION - (fakeLocation in citiesRepository.citiesLocationsList && !isSpecificLocation) -> - LocationMode.RANDOM_LOCATION + fakeLocation in citiesRepository.citiesLocationsList && !isSpecificLocation -> LocationMode.RANDOM_LOCATION else -> LocationMode.SPECIFIC_LOCATION } @@ -102,7 +101,9 @@ class FakeLocationStateUseCase( localStateRepository.updateFakeLocationWhitelist(emptySet()) } - fun canResetBlacklist(): Flow = localStateRepository.fakeLocationWhitelistedApps.map { it.isNotEmpty() } + fun canResetBlacklist(): Flow = localStateRepository.fakeLocationWhitelistedApps.map { + it.isNotEmpty() + } fun appsWithBlacklist(): Flow> { return combine( diff --git a/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/ListenLocationUseCase.kt b/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/ListenLocationUseCase.kt index e636c4eb..7475cb67 100644 --- a/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/ListenLocationUseCase.kt +++ b/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/ListenLocationUseCase.kt @@ -21,10 +21,10 @@ import android.content.pm.PackageManager import android.location.Location import android.location.LocationListener import android.location.LocationManager -import android.os.Bundle import foundation.e.advancedprivacy.domain.entities.ApplicationDescription import foundation.e.advancedprivacy.externalinterfaces.permissions.IPermissionsPrivacyModule import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.update import timber.log.Timber @@ -33,25 +33,28 @@ class ListenLocationUseCase( private val appContext: Context, private val appDesc: ApplicationDescription ) { + companion object { + const val MIN_TIME_INTERVAL = 1000L + const val MIN_DIST_INTERVAL = 0f + } + private val locationManager: LocationManager - get() = appContext.getSystemService(Context.LOCATION_SERVICE) as LocationManager + get() = appContext.getSystemService(LocationManager::class.java) as LocationManager private fun hasAcquireLocationPermission(): Boolean { return (appContext.checkSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) || permissionsModule.toggleDangerousPermission(appDesc, android.Manifest.permission.ACCESS_FINE_LOCATION, true) } - val currentLocation = MutableStateFlow(null) + private val _currentLocation = MutableStateFlow(null) + val currentLocation: StateFlow = _currentLocation private var localListener = object : LocationListener { override fun onLocationChanged(location: Location) { - currentLocation.update { location } + _currentLocation.update { location } } - @Deprecated("Deprecated since API 29, never called.") - override fun onStatusChanged(provider: String?, status: Int, extras: Bundle?) {} - override fun onProviderEnabled(provider: String) { reset() } @@ -62,7 +65,7 @@ class ListenLocationUseCase( private fun reset() { stopListeningLocation() - currentLocation.value = null + _currentLocation.value = null startListeningLocation() } } @@ -90,16 +93,16 @@ class ListenLocationUseCase( networkProvider?.let { locationManager.requestLocationUpdates( it, - 1000L, - 0f, + MIN_TIME_INTERVAL, + MIN_DIST_INTERVAL, localListener ) } gpsProvider?.let { locationManager.requestLocationUpdates( it, - 1000L, - 0f, + MIN_TIME_INTERVAL, + MIN_DIST_INTERVAL, localListener ) } diff --git a/app/src/main/java/foundation/e/advancedprivacy/externalinterfaces/contentproviders/FakeLocationContentProvider.kt b/app/src/main/java/foundation/e/advancedprivacy/externalinterfaces/contentproviders/FakeLocationContentProvider.kt index de7bc328..09b2c788 100644 --- a/app/src/main/java/foundation/e/advancedprivacy/externalinterfaces/contentproviders/FakeLocationContentProvider.kt +++ b/app/src/main/java/foundation/e/advancedprivacy/externalinterfaces/contentproviders/FakeLocationContentProvider.kt @@ -34,7 +34,7 @@ class FakeLocationContentProvider : ContentProvider() { override fun call(method: String, arg: String?, extras: Bundle?): Bundle? { val appUid = extras?.getInt(PARAM_UID, -1) ?: -1 - return fakeLocationForAppUseCase.getFakeLocationOrNull(arg!!, appUid)?.let { (lat, lon) -> + return fakeLocationForAppUseCase.getFakeLocationOrNull(arg, appUid)?.let { (lat, lon) -> Bundle().apply { putDouble(PARAM_LATITUDE, lat.toDouble()) putDouble(PARAM_LONGITUDE, lon.toDouble()) -- GitLab From 9f9e162b014ac04d4819c2d862b98a07d8603df9 Mon Sep 17 00:00:00 2001 From: jacquarg Date: Sat, 31 Aug 2024 09:42:06 +0200 Subject: [PATCH 5/8] feat:2396: MR fixes, improve code readability --- .../domain/usecases/ListenLocationUseCase.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/ListenLocationUseCase.kt b/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/ListenLocationUseCase.kt index 7475cb67..cd64be99 100644 --- a/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/ListenLocationUseCase.kt +++ b/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/ListenLocationUseCase.kt @@ -42,10 +42,14 @@ class ListenLocationUseCase( get() = appContext.getSystemService(LocationManager::class.java) as LocationManager private fun hasAcquireLocationPermission(): Boolean { - return (appContext.checkSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) || + return isAccessFineLocationGranted() || permissionsModule.toggleDangerousPermission(appDesc, android.Manifest.permission.ACCESS_FINE_LOCATION, true) } + private fun isAccessFineLocationGranted(): Boolean { + return appContext.checkSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED + } + private val _currentLocation = MutableStateFlow(null) val currentLocation: StateFlow = _currentLocation -- GitLab From 8b3cfb70b5903a91441c7fe9340e8146383c7d32 Mon Sep 17 00:00:00 2001 From: jacquarg Date: Mon, 2 Sep 2024 21:11:16 +0200 Subject: [PATCH 6/8] feat:2396: MR fixes, improve code style and readability. --- .../foundation/e/advancedprivacy/KoinModule.kt | 8 ++++---- .../domain/usecases/FakeLocationForAppUseCase.kt | 12 ++++++------ .../domain/usecases/FakeLocationStateUseCase.kt | 12 ++++++++---- .../domain/usecases/IpScramblingStateUseCase.kt | 6 +++--- .../domain/usecases/TrackerDetailsUseCase.kt | 6 +++--- .../domain/usecases/TrackersAndAppsListsUseCase.kt | 10 +++++----- .../domain/usecases/TrackersStatisticsUseCase.kt | 6 +++--- .../e/advancedprivacy/core/KoinModule.kt | 4 ++-- ...{AppListsRepository.kt => AppListRepository.kt} | 2 +- .../e/advancedprivacy/trackers/KoinModule.kt | 4 ++-- .../trackers/data/WhitelistRepository.kt | 14 +++++++------- .../domain/usecases/FilterHostnameUseCase.kt | 6 +++--- 12 files changed, 47 insertions(+), 43 deletions(-) rename core/src/main/java/foundation/e/advancedprivacy/data/repositories/{AppListsRepository.kt => AppListRepository.kt} (99%) diff --git a/app/src/main/java/foundation/e/advancedprivacy/KoinModule.kt b/app/src/main/java/foundation/e/advancedprivacy/KoinModule.kt index 5d426a36..e0a6ba57 100644 --- a/app/src/main/java/foundation/e/advancedprivacy/KoinModule.kt +++ b/app/src/main/java/foundation/e/advancedprivacy/KoinModule.kt @@ -21,7 +21,7 @@ import android.content.res.Resources import android.graphics.drawable.Drawable import android.os.Process import foundation.e.advancedprivacy.core.coreModule -import foundation.e.advancedprivacy.data.repositories.AppListsRepository +import foundation.e.advancedprivacy.data.repositories.AppListRepository import foundation.e.advancedprivacy.data.repositories.LocalStateRepositoryImpl import foundation.e.advancedprivacy.data.repositories.ResourcesRepository import foundation.e.advancedprivacy.domain.entities.ApplicationDescription @@ -131,7 +131,7 @@ val appModule = module { IpScramblingStateUseCase( orbotSupervisor = get(), localStateRepository = get(), - appListsRepository = get(), + appListRepository = get(), backgroundScope = get() ) } @@ -152,8 +152,8 @@ val appModule = module { } viewModel { parameters -> - val appListsRepository: AppListsRepository = get() - val app = appListsRepository.getAppById(parameters.get()) ?: DisplayableApp( + val appListRepository: AppListRepository = get() + val app = appListRepository.getAppById(parameters.get()) ?: DisplayableApp( id = "dummy-app", label = androidContext().resources.getString(R.string.app_name), icon = get(named("SystemAppIcon")), diff --git a/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/FakeLocationForAppUseCase.kt b/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/FakeLocationForAppUseCase.kt index d1b4ebee..43036bc1 100644 --- a/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/FakeLocationForAppUseCase.kt +++ b/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/FakeLocationForAppUseCase.kt @@ -16,18 +16,18 @@ */ package foundation.e.advancedprivacy.domain.usecases -import foundation.e.advancedprivacy.data.repositories.AppListsRepository +import foundation.e.advancedprivacy.data.repositories.AppListRepository import foundation.e.advancedprivacy.domain.repositories.LocalStateRepository class FakeLocationForAppUseCase( - private val appListsRepository: AppListsRepository, + private val appListRepository: AppListRepository, private val localStateRepository: LocalStateRepository ) { private val nullFakeLocationPkgs = listOf( - AppListsRepository.PNAME_MICROG_SERVICES_CORE, - AppListsRepository.PNAME_FUSED_LOCATION, - AppListsRepository.PNAME_ANDROID_SYSTEM + AppListRepository.PNAME_MICROG_SERVICES_CORE, + AppListRepository.PNAME_FUSED_LOCATION, + AppListRepository.PNAME_ANDROID_SYSTEM ) fun getFakeLocationOrNull(packageName: String?, uid: Int): Pair? { @@ -35,7 +35,7 @@ class FakeLocationForAppUseCase( return null } - val app = appListsRepository.getApp(uid) + val app = appListRepository.getApp(uid) return if (app?.apId != null && app.apId in localStateRepository.fakeLocationWhitelistedApps.value) { null } else { 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 5dd158c0..d0a88eb4 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 @@ -18,7 +18,7 @@ package foundation.e.advancedprivacy.domain.usecases -import foundation.e.advancedprivacy.data.repositories.AppListsRepository +import foundation.e.advancedprivacy.data.repositories.AppListRepository import foundation.e.advancedprivacy.domain.entities.DisplayableApp import foundation.e.advancedprivacy.domain.entities.LocationMode import foundation.e.advancedprivacy.domain.entities.ToggleableApp @@ -36,7 +36,7 @@ import kotlinx.coroutines.launch class FakeLocationStateUseCase( private val localStateRepository: LocalStateRepository, private val citiesRepository: CityDataSource, - private val appListsRepository: AppListsRepository, + private val appListRepository: AppListRepository, coroutineScope: CoroutineScope ) { private val _configuredLocationMode = MutableStateFlow>( @@ -55,13 +55,17 @@ class FakeLocationStateUseCase( private fun applySettings(isEnabled: Boolean, fakeLocation: Pair, isSpecificLocation: Boolean = false) { val locationMode = when { !isEnabled -> LocationMode.REAL_LOCATION - fakeLocation in citiesRepository.citiesLocationsList && !isSpecificLocation -> LocationMode.RANDOM_LOCATION + isRandomLocation(fakeLocation, !isSpecificLocation) -> LocationMode.RANDOM_LOCATION else -> LocationMode.SPECIFIC_LOCATION } _configuredLocationMode.value = Triple(locationMode, fakeLocation.first, fakeLocation.second) } + private fun isRandomLocation(fakeLocation: Pair, isSpecificLocation: Boolean): Boolean { + return fakeLocation in citiesRepository.citiesLocationsList && !isSpecificLocation + } + fun setSpecificLocation(latitude: Float, longitude: Float) { setFakeLocation(latitude to longitude, true) } @@ -107,7 +111,7 @@ class FakeLocationStateUseCase( fun appsWithBlacklist(): Flow> { return combine( - appListsRepository.displayableApps.map { apps -> + appListRepository.displayableApps.map { apps -> apps.filter { it.hasLocationPermission }.sortedBy { it.label.toString() } }, localStateRepository.fakeLocationWhitelistedApps diff --git a/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/IpScramblingStateUseCase.kt b/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/IpScramblingStateUseCase.kt index c8e21040..dca8625a 100644 --- a/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/IpScramblingStateUseCase.kt +++ b/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/IpScramblingStateUseCase.kt @@ -18,7 +18,7 @@ package foundation.e.advancedprivacy.domain.usecases -import foundation.e.advancedprivacy.data.repositories.AppListsRepository +import foundation.e.advancedprivacy.data.repositories.AppListRepository import foundation.e.advancedprivacy.domain.entities.DisplayableApp import foundation.e.advancedprivacy.domain.entities.FeatureState import foundation.e.advancedprivacy.domain.entities.ProfileType @@ -37,7 +37,7 @@ import kotlinx.coroutines.flow.update class IpScramblingStateUseCase( private val orbotSupervisor: OrbotSupervisor, private val localStateRepository: LocalStateRepository, - private val appListsRepository: AppListsRepository, + private val appListRepository: AppListRepository, private val backgroundScope: CoroutineScope ) { val internetPrivacyMode: StateFlow = orbotSupervisor.state @@ -62,7 +62,7 @@ class IpScramblingStateUseCase( suspend fun getTorToggleableApp(): Flow> { return combine( - appListsRepository.displayableApps.map { apps -> + appListRepository.displayableApps.map { apps -> apps.filter { app -> app.hasInternetPermission && app.profileType == ProfileType.MAIN } diff --git a/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/TrackerDetailsUseCase.kt b/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/TrackerDetailsUseCase.kt index b2959f7d..e94ee3df 100644 --- a/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/TrackerDetailsUseCase.kt +++ b/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/TrackerDetailsUseCase.kt @@ -17,7 +17,7 @@ */ package foundation.e.advancedprivacy.domain.usecases -import foundation.e.advancedprivacy.data.repositories.AppListsRepository +import foundation.e.advancedprivacy.data.repositories.AppListRepository import foundation.e.advancedprivacy.domain.entities.DisplayableApp import foundation.e.advancedprivacy.domain.entities.ToggleableApp import foundation.e.advancedprivacy.trackers.data.StatsDatabase @@ -28,7 +28,7 @@ import foundation.e.advancedprivacy.trackers.domain.usecases.FilterHostnameUseCa class TrackerDetailsUseCase( private val whitelistRepository: WhitelistRepository, private val trackersStateUseCase: TrackersStateUseCase, - private val appListsRepository: AppListsRepository, + private val appListRepository: AppListRepository, private val statsDatabase: StatsDatabase, private val filterHostnameUseCase: FilterHostnameUseCase ) { @@ -45,7 +45,7 @@ class TrackerDetailsUseCase( suspend fun getAppsWithBlockedState(tracker: Tracker): List { return enrichWithBlockedState( statsDatabase.getApIds(tracker.id).mapNotNull { - appListsRepository.getInternetAppByApId(it) + appListRepository.getInternetAppByApId(it) }.distinct().sortedBy { it.label.toString() }, tracker ) diff --git a/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/TrackersAndAppsListsUseCase.kt b/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/TrackersAndAppsListsUseCase.kt index 408247c2..bdfef3b1 100644 --- a/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/TrackersAndAppsListsUseCase.kt +++ b/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/TrackersAndAppsListsUseCase.kt @@ -16,7 +16,7 @@ */ package foundation.e.advancedprivacy.domain.usecases -import foundation.e.advancedprivacy.data.repositories.AppListsRepository +import foundation.e.advancedprivacy.data.repositories.AppListRepository import foundation.e.advancedprivacy.domain.entities.AppWithCount import foundation.e.advancedprivacy.domain.entities.DisplayableApp import foundation.e.advancedprivacy.domain.entities.TrackerWithCount @@ -31,7 +31,7 @@ import kotlinx.coroutines.flow.first class TrackersAndAppsListsUseCase( private val statsDatabase: StatsDatabase, private val trackersRepository: TrackersRepository, - private val appListsRepository: AppListsRepository + private val appListRepository: AppListRepository ) { suspend fun getAppsAndTrackersCounts(period: Period): TrackersAndAppsLists { val countByEntitiesMaps = getCountByEntityMaps(period) @@ -64,7 +64,7 @@ class TrackersAndAppsListsUseCase( val countByApps = mutableMapOf() countByApIds.forEach { (apId, count) -> - appListsRepository.getInternetAppByApId(apId)?.let { app -> + appListRepository.getInternetAppByApId(apId)?.let { app -> countByApps[app] = count + (countByApps[app] ?: 0) } } @@ -87,7 +87,7 @@ class TrackersAndAppsListsUseCase( } private suspend fun buildAllAppList(countByApp: Map): List { - return appListsRepository.displayableApps.first() + return appListRepository.displayableApps.first() .filter { it.hasInternetPermission } .map { app: DisplayableApp -> AppWithCount(app = app, count = countByApp[app] ?: 0) @@ -103,7 +103,7 @@ class TrackersAndAppsListsUseCase( private suspend fun mapIdsToEntities(trackersAndAppsIds: List>): List> { return trackersAndAppsIds.mapNotNull { (trackerId, apId) -> trackersRepository.getTracker(trackerId)?.let { tracker -> - appListsRepository.getInternetAppByApId(apId)?.let { app -> + appListRepository.getInternetAppByApId(apId)?.let { app -> tracker to app } } diff --git a/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/TrackersStatisticsUseCase.kt b/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/TrackersStatisticsUseCase.kt index 14a77ea1..35b1eaec 100644 --- a/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/TrackersStatisticsUseCase.kt +++ b/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/TrackersStatisticsUseCase.kt @@ -20,7 +20,7 @@ package foundation.e.advancedprivacy.domain.usecases import foundation.e.advancedprivacy.R import foundation.e.advancedprivacy.common.throttleFirst -import foundation.e.advancedprivacy.data.repositories.AppListsRepository +import foundation.e.advancedprivacy.data.repositories.AppListRepository import foundation.e.advancedprivacy.data.repositories.ResourcesRepository import foundation.e.advancedprivacy.domain.entities.ApplicationDescription import foundation.e.advancedprivacy.domain.entities.DisplayableApp @@ -40,12 +40,12 @@ import kotlinx.coroutines.flow.onStart class TrackersStatisticsUseCase( private val whitelistRepository: WhitelistRepository, private val trackersRepository: TrackersRepository, - private val appListsRepository: AppListsRepository, + private val appListRepository: AppListRepository, private val statsDatabase: StatsDatabase, private val resourcesRepository: ResourcesRepository ) { fun initAppList() { - appListsRepository.refreshAppDescriptions() + appListRepository.refreshAppDescriptions() } @OptIn(FlowPreview::class) diff --git a/core/src/main/java/foundation/e/advancedprivacy/core/KoinModule.kt b/core/src/main/java/foundation/e/advancedprivacy/core/KoinModule.kt index 2c3e98f8..d9f01c7f 100644 --- a/core/src/main/java/foundation/e/advancedprivacy/core/KoinModule.kt +++ b/core/src/main/java/foundation/e/advancedprivacy/core/KoinModule.kt @@ -18,14 +18,14 @@ package foundation.e.advancedprivacy.core -import foundation.e.advancedprivacy.data.repositories.AppListsRepository +import foundation.e.advancedprivacy.data.repositories.AppListRepository import org.koin.android.ext.koin.androidContext import org.koin.core.qualifier.named import org.koin.dsl.module val coreModule = module { single { - AppListsRepository( + AppListRepository( permissionsModule = get(), context = androidContext(), compatibilityAppLabel = get(named("CompatibilityAppLabel")), diff --git a/core/src/main/java/foundation/e/advancedprivacy/data/repositories/AppListsRepository.kt b/core/src/main/java/foundation/e/advancedprivacy/data/repositories/AppListRepository.kt similarity index 99% rename from core/src/main/java/foundation/e/advancedprivacy/data/repositories/AppListsRepository.kt rename to core/src/main/java/foundation/e/advancedprivacy/data/repositories/AppListRepository.kt index aa16f3e4..9000fdcf 100644 --- a/core/src/main/java/foundation/e/advancedprivacy/data/repositories/AppListsRepository.kt +++ b/core/src/main/java/foundation/e/advancedprivacy/data/repositories/AppListRepository.kt @@ -37,7 +37,7 @@ import kotlinx.coroutines.joinAll import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking -class AppListsRepository( +class AppListRepository( private val permissionsModule: IPermissionsPrivacyModule, private val context: Context, private val compatibilityAppLabel: CharSequence, diff --git a/trackers/src/main/java/foundation/e/advancedprivacy/trackers/KoinModule.kt b/trackers/src/main/java/foundation/e/advancedprivacy/trackers/KoinModule.kt index e8a4da0b..4d5a80cb 100644 --- a/trackers/src/main/java/foundation/e/advancedprivacy/trackers/KoinModule.kt +++ b/trackers/src/main/java/foundation/e/advancedprivacy/trackers/KoinModule.kt @@ -42,7 +42,7 @@ val trackersModule = module { single { WhitelistRepository( context = androidContext(), - appListsRepository = get() + appListRepository = get() ) } @@ -53,7 +53,7 @@ val trackersModule = module { appDesc = get(named("AdvancedPrivacy")), context = androidContext(), database = get(), - appListsRepository = get() + appListRepository = get() ) } } diff --git a/trackers/src/main/java/foundation/e/advancedprivacy/trackers/data/WhitelistRepository.kt b/trackers/src/main/java/foundation/e/advancedprivacy/trackers/data/WhitelistRepository.kt index 618c4113..4a4d3375 100644 --- a/trackers/src/main/java/foundation/e/advancedprivacy/trackers/data/WhitelistRepository.kt +++ b/trackers/src/main/java/foundation/e/advancedprivacy/trackers/data/WhitelistRepository.kt @@ -20,7 +20,7 @@ package foundation.e.advancedprivacy.trackers.data import android.content.Context import android.content.SharedPreferences -import foundation.e.advancedprivacy.data.repositories.AppListsRepository +import foundation.e.advancedprivacy.data.repositories.AppListRepository import foundation.e.advancedprivacy.domain.entities.ApplicationDescription import foundation.e.advancedprivacy.trackers.domain.entities.Tracker import java.io.File @@ -30,7 +30,7 @@ import kotlinx.coroutines.withContext class WhitelistRepository( context: Context, - private val appListsRepository: AppListsRepository + private val appListRepository: AppListRepository ) { private var appsWhitelist: Set = HashSet() private var appUidsWhitelist: Set = HashSet() @@ -86,7 +86,7 @@ class WhitelistRepository( val apIds = prefsV1.getStringSet(KEY_APPS_WHITELIST, HashSet())?.mapNotNull { try { val uid = it.toInt() - appListsRepository.getApp(uid)?.apId + appListRepository.getApp(uid)?.apId } catch (e: Exception) { null } @@ -98,7 +98,7 @@ class WhitelistRepository( if (key.startsWith(KEY_APP_TRACKERS_WHITELIST_PREFIX)) { try { val uid = key.substring(KEY_APP_TRACKERS_WHITELIST_PREFIX.length).toInt() - val apId = appListsRepository.getApp(uid)?.apId + val apId = appListRepository.getApp(uid)?.apId apId?.let { val trackers = prefsV1.getStringSet(key, emptySet()) editorV2.putStringSet(KEY_APP_TRACKERS_WHITELIST_PREFIX + apId, trackers) @@ -151,7 +151,7 @@ class WhitelistRepository( private fun reloadAppsWhiteList() { appsWhitelist = prefs.getStringSet(KEY_APPS_WHITELIST, HashSet()) ?: HashSet() appUidsWhitelist = appsWhitelist - .mapNotNull { apId -> appListsRepository.getApp(apId)?.uid } + .mapNotNull { apId -> appListRepository.getApp(apId)?.uid } .toSet() } @@ -172,7 +172,7 @@ class WhitelistRepository( apIdTrackersWhitelist = whitelist appUidTrackersWhitelist = whitelist.mapNotNull { (apIdTrackerId, isWhitelisted) -> val (apId, tracker) = parseApIdTrackerKey(apIdTrackerId) - appListsRepository.getApp(apId)?.uid?.let { uid -> + appListRepository.getApp(apId)?.uid?.let { uid -> buildAppUidTrackerKey(uid, tracker) to isWhitelisted } }.toMap() @@ -280,7 +280,7 @@ class WhitelistRepository( } fun getWhiteListedApp(): List { - return appsWhitelist.mapNotNull(appListsRepository::getApp) + return appsWhitelist.mapNotNull(appListRepository::getApp) } fun getWhiteListForApp(app: ApplicationDescription): List { diff --git a/trackers/src/main/java/foundation/e/advancedprivacy/trackers/domain/usecases/FilterHostnameUseCase.kt b/trackers/src/main/java/foundation/e/advancedprivacy/trackers/domain/usecases/FilterHostnameUseCase.kt index f8c351c7..d4650be9 100644 --- a/trackers/src/main/java/foundation/e/advancedprivacy/trackers/domain/usecases/FilterHostnameUseCase.kt +++ b/trackers/src/main/java/foundation/e/advancedprivacy/trackers/domain/usecases/FilterHostnameUseCase.kt @@ -19,7 +19,7 @@ package foundation.e.advancedprivacy.trackers.domain.usecases import android.content.Context import android.content.pm.PackageManager import foundation.e.advancedprivacy.core.utils.runSuspendCatching -import foundation.e.advancedprivacy.data.repositories.AppListsRepository +import foundation.e.advancedprivacy.data.repositories.AppListRepository import foundation.e.advancedprivacy.domain.entities.ApplicationDescription import foundation.e.advancedprivacy.trackers.data.StatsDatabase import foundation.e.advancedprivacy.trackers.data.TrackersRepository @@ -38,7 +38,7 @@ class FilterHostnameUseCase( context: Context, private val appDesc: ApplicationDescription, private val database: StatsDatabase, - private val appListsRepository: AppListsRepository + private val appListRepository: AppListRepository ) { private var eBrowserAppUid = -1 @@ -95,7 +95,7 @@ class FilterHostnameUseCase( private val queue = LinkedBlockingQueue() private suspend fun logAccess(detectedTracker: DetectedTracker) { - appListsRepository.getApp(detectedTracker.appUid)?.let { app -> + appListRepository.getApp(detectedTracker.appUid)?.let { app -> database.logAccess(detectedTracker.trackerId, app.apId, detectedTracker.wasBlocked) } } -- GitLab From 7c21ecc7caf6e1553f7455b072dbaa9bdbb5ad9d Mon Sep 17 00:00:00 2001 From: jacquarg Date: Mon, 9 Sep 2024 09:23:03 +0200 Subject: [PATCH 7/8] feat:2396: MR fix, improve code style. --- .../features/trackers/apptrackers/AppTrackersViewModel.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/foundation/e/advancedprivacy/features/trackers/apptrackers/AppTrackersViewModel.kt b/app/src/main/java/foundation/e/advancedprivacy/features/trackers/apptrackers/AppTrackersViewModel.kt index 87b12e38..8ccdd98a 100644 --- a/app/src/main/java/foundation/e/advancedprivacy/features/trackers/apptrackers/AppTrackersViewModel.kt +++ b/app/src/main/java/foundation/e/advancedprivacy/features/trackers/apptrackers/AppTrackersViewModel.kt @@ -35,6 +35,7 @@ import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.merge import kotlinx.coroutines.flow.update @@ -68,7 +69,7 @@ class AppTrackersViewModel( _state.update { s -> s.copy(isTrackersBlockingEnabled = it != FeatureMode.VULNERABLE) } }, trackersStatisticsUseCase.listenUpdates().map { fetchStatistics() } - ).collect { } + ).collect() } fun onClickLearnMore() { -- GitLab From bb968d2ab5165a89a9b4cf780b8fd70e6b9e0a90 Mon Sep 17 00:00:00 2001 From: jacquarg Date: Mon, 16 Sep 2024 21:42:00 +0200 Subject: [PATCH 8/8] feat:2396: Add permission on fakelocation contentprovider, fix random location selector --- app/src/main/AndroidManifest.xml | 3 +++ .../domain/usecases/FakeLocationStateUseCase.kt | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b9ccdb6f..2a5a4ed4 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -34,6 +34,8 @@ tools:ignore="QueryAllPackagesPermission" /> + + 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 d0a88eb4..8b96664f 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 @@ -55,7 +55,7 @@ class FakeLocationStateUseCase( private fun applySettings(isEnabled: Boolean, fakeLocation: Pair, isSpecificLocation: Boolean = false) { val locationMode = when { !isEnabled -> LocationMode.REAL_LOCATION - isRandomLocation(fakeLocation, !isSpecificLocation) -> LocationMode.RANDOM_LOCATION + isRandomLocation(fakeLocation, isSpecificLocation) -> LocationMode.RANDOM_LOCATION else -> LocationMode.SPECIFIC_LOCATION } -- GitLab