From ca0e548985a10abbeaca045ad254cef5170ea553 Mon Sep 17 00:00:00 2001 From: Guillaume Jacquart Date: Wed, 16 Aug 2023 09:29:26 +0200 Subject: [PATCH 1/5] Create core submodule, move files to clean archi tree in submodules. --- .../e/advancedprivacy/Notifications.kt | 6 +++--- .../common/ToggleAppsAdapter.kt | 2 +- .../data/repositories/LocalStateRepository.kt | 2 +- .../domain/entities/AppWithCounts.kt | 1 - .../domain/usecases/AppListUseCase.kt | 2 +- .../usecases/FakeLocationStateUseCase.kt | 12 +++++------ .../usecases/GetQuickPrivacyStateUseCase.kt | 4 ++-- .../internetprivacy/InternetPrivacyState.kt | 2 +- .../InternetPrivacyViewModel.kt | 4 ++-- .../trackers/apptrackers/AppTrackersState.kt | 4 ++-- .../apptrackers/AppTrackersViewModel.kt | 4 ++-- .../apptrackers/ToggleTrackersAdapter.kt | 2 +- core/.gitignore | 1 + core/consumer-rules.pro | 0 core/proguard-rules.pro | 21 +++++++++++++++++++ .../src/main/AndroidManifest.xml | 3 ++- .../domain/entities}/AppOpModes.kt | 2 +- .../entities}/ApplicationDescription.kt | 2 +- .../domain/entities}/PermissionDescription.kt | 2 +- .../permissions/APermissionsPrivacyModule.kt | 10 ++++----- .../permissions/IPermissionsPrivacyModule.kt | 11 +++++----- fakelocation/src/main/AndroidManifest.xml | 3 ++- .../domain/usecases}/FakeLocationModule.kt | 11 +++++----- .../services}/FakeLocationService.kt | 3 ++- permissionse/src/main/AndroidManifest.xml | 19 ++++++++++++++++- .../permissions/PermissionsPrivacyModule.kt | 11 +++++----- .../src/main/AndroidManifest.xml | 3 ++- .../PermissionsPrivacyModule.kt | 7 ++++--- trackers/src/main/AndroidManifest.xml | 5 +++-- .../trackers/domain/entities}/Tracker.kt | 2 +- .../trackers/services}/ForegroundStarter.kt | 2 +- 31 files changed, 104 insertions(+), 59 deletions(-) create mode 100644 core/.gitignore create mode 100644 core/consumer-rules.pro create mode 100644 core/proguard-rules.pro rename {privacymodule-api => core}/src/main/AndroidManifest.xml (90%) rename {privacymodule-api/src/main/java/foundation/e/privacymodules/permissions/data => core/src/main/java/foundation/e/advancedprivacy/domain/entities}/AppOpModes.kt (96%) rename {privacymodule-api/src/main/java/foundation/e/privacymodules/permissions/data => core/src/main/java/foundation/e/advancedprivacy/domain/entities}/ApplicationDescription.kt (96%) rename {privacymodule-api/src/main/java/foundation/e/privacymodules/permissions/data => core/src/main/java/foundation/e/advancedprivacy/domain/entities}/PermissionDescription.kt (94%) rename {privacymodule-api/src/main/java/foundation/e/privacymodules => core/src/main/java/foundation/e/advancedprivacy/externalinterfaces}/permissions/APermissionsPrivacyModule.kt (94%) rename {privacymodule-api/src/main/java/foundation/e/privacymodules => core/src/main/java/foundation/e/advancedprivacy/externalinterfaces}/permissions/IPermissionsPrivacyModule.kt (93%) rename fakelocation/src/main/java/foundation/e/{privacymodules/fakelocation => advancedprivacy/fakelocation/domain/usecases}/FakeLocationModule.kt (93%) rename fakelocation/src/main/java/foundation/e/{privacymodules/fakelocation => advancedprivacy/fakelocation/services}/FakeLocationService.kt (96%) rename permissionse/src/main/java/foundation/e/{privacymodules => advancedprivacy/externalinterfaces}/permissions/PermissionsPrivacyModule.kt (95%) rename permissionsstandalone/src/main/java/foundation/e/{privacymodules/permissions => advancedprivacy/permissions/externalinterfaces}/PermissionsPrivacyModule.kt (88%) rename trackers/src/main/java/foundation/e/{privacymodules/trackers/api => advancedprivacy/trackers/domain/entities}/Tracker.kt (93%) rename trackers/src/main/java/foundation/e/{privacymodules/trackers => advancedprivacy/trackers/services}/ForegroundStarter.kt (96%) diff --git a/app/src/main/java/foundation/e/advancedprivacy/Notifications.kt b/app/src/main/java/foundation/e/advancedprivacy/Notifications.kt index 291f9bca..cd85e9a6 100644 --- a/app/src/main/java/foundation/e/advancedprivacy/Notifications.kt +++ b/app/src/main/java/foundation/e/advancedprivacy/Notifications.kt @@ -28,8 +28,8 @@ import androidx.core.app.NotificationManagerCompat import foundation.e.advancedprivacy.domain.entities.InternetPrivacyMode import foundation.e.advancedprivacy.domain.entities.MainFeatures import foundation.e.advancedprivacy.domain.usecases.GetQuickPrivacyStateUseCase +import foundation.e.advancedprivacy.externalinterfaces.permissions.IPermissionsPrivacyModule import foundation.e.advancedprivacy.main.MainActivity -import foundation.e.privacymodules.permissions.PermissionsPrivacyModule import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.launchIn @@ -69,7 +69,7 @@ object Notifications { fun startListening( appContext: Context, getQuickPrivacyStateUseCase: GetQuickPrivacyStateUseCase, - permissionsPrivacyModule: PermissionsPrivacyModule, + permissionsPrivacyModule: IPermissionsPrivacyModule, appScope: CoroutineScope ) { createNotificationFlagChannel( @@ -118,7 +118,7 @@ object Notifications { private fun createNotificationFlagChannel( context: Context, - permissionsPrivacyModule: PermissionsPrivacyModule, + permissionsPrivacyModule: IPermissionsPrivacyModule, channelId: String, @StringRes channelName: Int, @StringRes channelDescription: Int, diff --git a/app/src/main/java/foundation/e/advancedprivacy/common/ToggleAppsAdapter.kt b/app/src/main/java/foundation/e/advancedprivacy/common/ToggleAppsAdapter.kt index d8ee8ea0..8a0cc83d 100644 --- a/app/src/main/java/foundation/e/advancedprivacy/common/ToggleAppsAdapter.kt +++ b/app/src/main/java/foundation/e/advancedprivacy/common/ToggleAppsAdapter.kt @@ -25,7 +25,7 @@ import android.widget.ImageView import android.widget.TextView import androidx.recyclerview.widget.RecyclerView import foundation.e.advancedprivacy.R -import foundation.e.privacymodules.permissions.data.ApplicationDescription +import foundation.e.advancedprivacy.domain.entities.ApplicationDescription class ToggleAppsAdapter( private val itemsLayout: Int, diff --git a/app/src/main/java/foundation/e/advancedprivacy/data/repositories/LocalStateRepository.kt b/app/src/main/java/foundation/e/advancedprivacy/data/repositories/LocalStateRepository.kt index 3f73c789..ba2836fd 100644 --- a/app/src/main/java/foundation/e/advancedprivacy/data/repositories/LocalStateRepository.kt +++ b/app/src/main/java/foundation/e/advancedprivacy/data/repositories/LocalStateRepository.kt @@ -18,9 +18,9 @@ package foundation.e.advancedprivacy.data.repositories import android.content.Context +import foundation.e.advancedprivacy.domain.entities.ApplicationDescription import foundation.e.advancedprivacy.domain.entities.InternetPrivacyMode import foundation.e.advancedprivacy.domain.entities.LocationMode -import foundation.e.privacymodules.permissions.data.ApplicationDescription import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharedFlow diff --git a/app/src/main/java/foundation/e/advancedprivacy/domain/entities/AppWithCounts.kt b/app/src/main/java/foundation/e/advancedprivacy/domain/entities/AppWithCounts.kt index 4169ecc0..344e6897 100644 --- a/app/src/main/java/foundation/e/advancedprivacy/domain/entities/AppWithCounts.kt +++ b/app/src/main/java/foundation/e/advancedprivacy/domain/entities/AppWithCounts.kt @@ -19,7 +19,6 @@ package foundation.e.advancedprivacy.domain.entities import android.graphics.drawable.Drawable -import foundation.e.privacymodules.permissions.data.ApplicationDescription data class AppWithCounts( val appDesc: ApplicationDescription, diff --git a/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/AppListUseCase.kt b/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/AppListUseCase.kt index 8d38ee8f..dfd32b6c 100644 --- a/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/AppListUseCase.kt +++ b/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/AppListUseCase.kt @@ -18,7 +18,7 @@ package foundation.e.advancedprivacy.domain.usecases import foundation.e.advancedprivacy.data.repositories.AppListsRepository -import foundation.e.privacymodules.permissions.data.ApplicationDescription +import foundation.e.advancedprivacy.domain.entities.ApplicationDescription import kotlinx.coroutines.flow.Flow class AppListUseCase( 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 8831fff5..30c8e6ba 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 @@ -26,12 +26,12 @@ import android.location.LocationListener import android.location.LocationManager import android.os.Bundle import foundation.e.advancedprivacy.data.repositories.LocalStateRepository +import foundation.e.advancedprivacy.domain.entities.AppOpModes +import foundation.e.advancedprivacy.domain.entities.ApplicationDescription import foundation.e.advancedprivacy.domain.entities.LocationMode import foundation.e.advancedprivacy.dummy.CityDataSource -import foundation.e.privacymodules.fakelocation.IFakeLocationModule -import foundation.e.privacymodules.permissions.PermissionsPrivacyModule -import foundation.e.privacymodules.permissions.data.AppOpModes -import foundation.e.privacymodules.permissions.data.ApplicationDescription +import foundation.e.advancedprivacy.externalinterfaces.permissions.IPermissionsPrivacyModule +import foundation.e.advancedprivacy.fakelocation.domain.usecases.FakeLocationModule import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -41,8 +41,8 @@ import timber.log.Timber import kotlin.random.Random class FakeLocationStateUseCase( - private val fakeLocationModule: IFakeLocationModule, - private val permissionsModule: PermissionsPrivacyModule, + private val fakeLocationModule: FakeLocationModule, + private val permissionsModule: IPermissionsPrivacyModule, private val localStateRepository: LocalStateRepository, private val citiesRepository: CityDataSource, private val appDesc: ApplicationDescription, diff --git a/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/GetQuickPrivacyStateUseCase.kt b/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/GetQuickPrivacyStateUseCase.kt index b82918e2..bc4871a8 100644 --- a/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/GetQuickPrivacyStateUseCase.kt +++ b/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/GetQuickPrivacyStateUseCase.kt @@ -18,11 +18,11 @@ package foundation.e.advancedprivacy.domain.usecases import foundation.e.advancedprivacy.data.repositories.LocalStateRepository +import foundation.e.advancedprivacy.domain.entities.ApplicationDescription import foundation.e.advancedprivacy.domain.entities.InternetPrivacyMode import foundation.e.advancedprivacy.domain.entities.LocationMode import foundation.e.advancedprivacy.domain.entities.QuickPrivacyState import foundation.e.advancedprivacy.domain.entities.TrackerMode -import foundation.e.privacymodules.permissions.data.ApplicationDescription import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.StateFlow @@ -30,7 +30,7 @@ import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.map class GetQuickPrivacyStateUseCase( - private val localStateRepository: LocalStateRepository + private val localStateRepository: LocalStateRepository, ) { val quickPrivacyState: Flow = combine( localStateRepository.blockTrackers, diff --git a/app/src/main/java/foundation/e/advancedprivacy/features/internetprivacy/InternetPrivacyState.kt b/app/src/main/java/foundation/e/advancedprivacy/features/internetprivacy/InternetPrivacyState.kt index e0df73be..4d0fb38b 100644 --- a/app/src/main/java/foundation/e/advancedprivacy/features/internetprivacy/InternetPrivacyState.kt +++ b/app/src/main/java/foundation/e/advancedprivacy/features/internetprivacy/InternetPrivacyState.kt @@ -17,8 +17,8 @@ package foundation.e.advancedprivacy.features.internetprivacy +import foundation.e.advancedprivacy.domain.entities.ApplicationDescription import foundation.e.advancedprivacy.domain.entities.InternetPrivacyMode -import foundation.e.privacymodules.permissions.data.ApplicationDescription data class InternetPrivacyState( val mode: InternetPrivacyMode = InternetPrivacyMode.REAL_IP, diff --git a/app/src/main/java/foundation/e/advancedprivacy/features/internetprivacy/InternetPrivacyViewModel.kt b/app/src/main/java/foundation/e/advancedprivacy/features/internetprivacy/InternetPrivacyViewModel.kt index 4c707a23..80e00bcd 100644 --- a/app/src/main/java/foundation/e/advancedprivacy/features/internetprivacy/InternetPrivacyViewModel.kt +++ b/app/src/main/java/foundation/e/advancedprivacy/features/internetprivacy/InternetPrivacyViewModel.kt @@ -25,7 +25,7 @@ import foundation.e.advancedprivacy.domain.entities.InternetPrivacyMode import foundation.e.advancedprivacy.domain.usecases.AppListUseCase import foundation.e.advancedprivacy.domain.usecases.GetQuickPrivacyStateUseCase import foundation.e.advancedprivacy.domain.usecases.IpScramblingStateUseCase -import foundation.e.privacymodules.ipscrambler.IIpScramblerModule +import foundation.e.advancedprivacy.ipscrambler.IpScramblerModule import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.flow.MutableSharedFlow @@ -40,7 +40,7 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.withContext class InternetPrivacyViewModel( - private val ipScramblerModule: IIpScramblerModule, + private val ipScramblerModule: IpScramblerModule, private val getQuickPrivacyStateUseCase: GetQuickPrivacyStateUseCase, private val ipScramblingStateUseCase: IpScramblingStateUseCase, private val appListUseCase: AppListUseCase diff --git a/app/src/main/java/foundation/e/advancedprivacy/features/trackers/apptrackers/AppTrackersState.kt b/app/src/main/java/foundation/e/advancedprivacy/features/trackers/apptrackers/AppTrackersState.kt index 2a9e6e82..a597da64 100644 --- a/app/src/main/java/foundation/e/advancedprivacy/features/trackers/apptrackers/AppTrackersState.kt +++ b/app/src/main/java/foundation/e/advancedprivacy/features/trackers/apptrackers/AppTrackersState.kt @@ -18,8 +18,8 @@ package foundation.e.advancedprivacy.features.trackers.apptrackers -import foundation.e.privacymodules.permissions.data.ApplicationDescription -import foundation.e.privacymodules.trackers.api.Tracker +import foundation.e.advancedprivacy.domain.entities.ApplicationDescription +import foundation.e.advancedprivacy.trackers.domain.entities.Tracker data class AppTrackersState( val appDesc: ApplicationDescription? = null, 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 cda4b4b9..87407792 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 @@ -22,12 +22,12 @@ import android.net.Uri import androidx.annotation.StringRes import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import foundation.e.advancedprivacy.domain.entities.ApplicationDescription import foundation.e.advancedprivacy.domain.entities.TrackerMode import foundation.e.advancedprivacy.domain.usecases.GetQuickPrivacyStateUseCase import foundation.e.advancedprivacy.domain.usecases.TrackersStateUseCase import foundation.e.advancedprivacy.domain.usecases.TrackersStatisticsUseCase -import foundation.e.privacymodules.permissions.data.ApplicationDescription -import foundation.e.privacymodules.trackers.api.Tracker +import foundation.e.advancedprivacy.trackers.domain.entities.Tracker import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow diff --git a/app/src/main/java/foundation/e/advancedprivacy/features/trackers/apptrackers/ToggleTrackersAdapter.kt b/app/src/main/java/foundation/e/advancedprivacy/features/trackers/apptrackers/ToggleTrackersAdapter.kt index 36969393..ef845b67 100644 --- a/app/src/main/java/foundation/e/advancedprivacy/features/trackers/apptrackers/ToggleTrackersAdapter.kt +++ b/app/src/main/java/foundation/e/advancedprivacy/features/trackers/apptrackers/ToggleTrackersAdapter.kt @@ -27,7 +27,7 @@ import android.widget.TextView import androidx.core.content.ContextCompat import androidx.recyclerview.widget.RecyclerView import foundation.e.advancedprivacy.R -import foundation.e.privacymodules.trackers.api.Tracker +import foundation.e.advancedprivacy.trackers.domain.entities.Tracker class ToggleTrackersAdapter( private val itemsLayout: Int, diff --git a/core/.gitignore b/core/.gitignore new file mode 100644 index 00000000..42afabfd --- /dev/null +++ b/core/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/core/consumer-rules.pro b/core/consumer-rules.pro new file mode 100644 index 00000000..e69de29b diff --git a/core/proguard-rules.pro b/core/proguard-rules.pro new file mode 100644 index 00000000..481bb434 --- /dev/null +++ b/core/proguard-rules.pro @@ -0,0 +1,21 @@ +# 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/privacymodule-api/src/main/AndroidManifest.xml b/core/src/main/AndroidManifest.xml similarity index 90% rename from privacymodule-api/src/main/AndroidManifest.xml rename to core/src/main/AndroidManifest.xml index 937e285d..a29e84cf 100644 --- a/privacymodule-api/src/main/AndroidManifest.xml +++ b/core/src/main/AndroidManifest.xml @@ -1,5 +1,6 @@ \ No newline at end of file diff --git a/privacymodule-api/src/main/java/foundation/e/privacymodules/permissions/data/AppOpModes.kt b/core/src/main/java/foundation/e/advancedprivacy/domain/entities/AppOpModes.kt similarity index 96% rename from privacymodule-api/src/main/java/foundation/e/privacymodules/permissions/data/AppOpModes.kt rename to core/src/main/java/foundation/e/advancedprivacy/domain/entities/AppOpModes.kt index 47645961..3e0a2611 100644 --- a/privacymodule-api/src/main/java/foundation/e/privacymodules/permissions/data/AppOpModes.kt +++ b/core/src/main/java/foundation/e/advancedprivacy/domain/entities/AppOpModes.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package foundation.e.privacymodules.permissions.data +package foundation.e.advancedprivacy.domain.entities import android.app.AppOpsManager.MODE_ALLOWED import android.app.AppOpsManager.MODE_DEFAULT diff --git a/privacymodule-api/src/main/java/foundation/e/privacymodules/permissions/data/ApplicationDescription.kt b/core/src/main/java/foundation/e/advancedprivacy/domain/entities/ApplicationDescription.kt similarity index 96% rename from privacymodule-api/src/main/java/foundation/e/privacymodules/permissions/data/ApplicationDescription.kt rename to core/src/main/java/foundation/e/advancedprivacy/domain/entities/ApplicationDescription.kt index 4fa1bb94..90b637f1 100644 --- a/privacymodule-api/src/main/java/foundation/e/privacymodules/permissions/data/ApplicationDescription.kt +++ b/core/src/main/java/foundation/e/advancedprivacy/domain/entities/ApplicationDescription.kt @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -package foundation.e.privacymodules.permissions.data +package foundation.e.advancedprivacy.domain.entities import android.graphics.drawable.Drawable diff --git a/privacymodule-api/src/main/java/foundation/e/privacymodules/permissions/data/PermissionDescription.kt b/core/src/main/java/foundation/e/advancedprivacy/domain/entities/PermissionDescription.kt similarity index 94% rename from privacymodule-api/src/main/java/foundation/e/privacymodules/permissions/data/PermissionDescription.kt rename to core/src/main/java/foundation/e/advancedprivacy/domain/entities/PermissionDescription.kt index 127192b9..c3899a93 100644 --- a/privacymodule-api/src/main/java/foundation/e/privacymodules/permissions/data/PermissionDescription.kt +++ b/core/src/main/java/foundation/e/advancedprivacy/domain/entities/PermissionDescription.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package foundation.e.privacymodules.permissions.data +package foundation.e.advancedprivacy.domain.entities data class PermissionDescription( val name: String, diff --git a/privacymodule-api/src/main/java/foundation/e/privacymodules/permissions/APermissionsPrivacyModule.kt b/core/src/main/java/foundation/e/advancedprivacy/externalinterfaces/permissions/APermissionsPrivacyModule.kt similarity index 94% rename from privacymodule-api/src/main/java/foundation/e/privacymodules/permissions/APermissionsPrivacyModule.kt rename to core/src/main/java/foundation/e/advancedprivacy/externalinterfaces/permissions/APermissionsPrivacyModule.kt index 64b22923..78f424b4 100644 --- a/privacymodule-api/src/main/java/foundation/e/privacymodules/permissions/APermissionsPrivacyModule.kt +++ b/core/src/main/java/foundation/e/advancedprivacy/externalinterfaces/permissions/APermissionsPrivacyModule.kt @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -package foundation.e.privacymodules.permissions +package foundation.e.advancedprivacy.externalinterfaces.permissions import android.app.AppOpsManager import android.content.Context @@ -27,10 +27,10 @@ import android.content.pm.PermissionInfo.PROTECTION_DANGEROUS import android.graphics.drawable.Drawable import android.os.Build import android.util.Log -import foundation.e.privacymodules.permissions.data.AppOpModes -import foundation.e.privacymodules.permissions.data.ApplicationDescription -import foundation.e.privacymodules.permissions.data.PermissionDescription -import foundation.e.privacymodules.permissions.data.ProfileType +import foundation.e.advancedprivacy.domain.entities.AppOpModes +import foundation.e.advancedprivacy.domain.entities.ApplicationDescription +import foundation.e.advancedprivacy.domain.entities.PermissionDescription +import foundation.e.advancedprivacy.domain.entities.ProfileType /** * Implementation of the commons functionality between privileged and standard diff --git a/privacymodule-api/src/main/java/foundation/e/privacymodules/permissions/IPermissionsPrivacyModule.kt b/core/src/main/java/foundation/e/advancedprivacy/externalinterfaces/permissions/IPermissionsPrivacyModule.kt similarity index 93% rename from privacymodule-api/src/main/java/foundation/e/privacymodules/permissions/IPermissionsPrivacyModule.kt rename to core/src/main/java/foundation/e/advancedprivacy/externalinterfaces/permissions/IPermissionsPrivacyModule.kt index 39c726ae..da11769e 100644 --- a/privacymodule-api/src/main/java/foundation/e/privacymodules/permissions/IPermissionsPrivacyModule.kt +++ b/core/src/main/java/foundation/e/advancedprivacy/externalinterfaces/permissions/IPermissionsPrivacyModule.kt @@ -15,17 +15,16 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - -package foundation.e.privacymodules.permissions +package foundation.e.advancedprivacy.externalinterfaces.permissions import android.app.NotificationChannel import android.content.pm.ApplicationInfo import android.content.pm.PackageInfo import android.graphics.drawable.Drawable -import foundation.e.privacymodules.permissions.data.AppOpModes -import foundation.e.privacymodules.permissions.data.ApplicationDescription -import foundation.e.privacymodules.permissions.data.PermissionDescription -import foundation.e.privacymodules.permissions.data.ProfileType +import foundation.e.advancedprivacy.domain.entities.AppOpModes +import foundation.e.advancedprivacy.domain.entities.ApplicationDescription +import foundation.e.advancedprivacy.domain.entities.PermissionDescription +import foundation.e.advancedprivacy.domain.entities.ProfileType /** * List applications and manage theirs permissions. diff --git a/fakelocation/src/main/AndroidManifest.xml b/fakelocation/src/main/AndroidManifest.xml index 5077c24d..fde371cb 100644 --- a/fakelocation/src/main/AndroidManifest.xml +++ b/fakelocation/src/main/AndroidManifest.xml @@ -1,5 +1,6 @@ + package="foundation.e.advancedprivacy.permissions.e"> diff --git a/permissionse/src/main/java/foundation/e/privacymodules/permissions/PermissionsPrivacyModule.kt b/permissionse/src/main/java/foundation/e/advancedprivacy/externalinterfaces/permissions/PermissionsPrivacyModule.kt similarity index 95% rename from permissionse/src/main/java/foundation/e/privacymodules/permissions/PermissionsPrivacyModule.kt rename to permissionse/src/main/java/foundation/e/advancedprivacy/externalinterfaces/permissions/PermissionsPrivacyModule.kt index 6d0a17cf..59a20dd7 100644 --- a/permissionse/src/main/java/foundation/e/privacymodules/permissions/PermissionsPrivacyModule.kt +++ b/permissionse/src/main/java/foundation/e/advancedprivacy/externalinterfaces/permissions/PermissionsPrivacyModule.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package foundation.e.privacymodules.permissions +package foundation.e.advancedprivacy.permissions.externalinterfaces import android.annotation.TargetApi import android.app.AppOpsManager @@ -35,10 +35,11 @@ import android.os.ServiceManager import android.os.UserHandle import android.os.UserManager import android.util.Log -import foundation.e.privacymodules.permissions.data.AppOpModes -import foundation.e.privacymodules.permissions.data.ApplicationDescription -import foundation.e.privacymodules.permissions.data.ProfileType.MAIN -import foundation.e.privacymodules.permissions.data.ProfileType.WORK +import foundation.e.advancedprivacy.domain.entities.AppOpModes +import foundation.e.advancedprivacy.domain.entities.ApplicationDescription +import foundation.e.advancedprivacy.domain.entities.ProfileType.MAIN +import foundation.e.advancedprivacy.domain.entities.ProfileType.WORK +import foundation.e.advancedprivacy.externalinterfaces.permissions.APermissionsPrivacyModule /** * Implements [IPermissionsPrivacyModule] with all privileges of a system app. diff --git a/permissionsstandalone/src/main/AndroidManifest.xml b/permissionsstandalone/src/main/AndroidManifest.xml index 662ea44a..60ff274f 100644 --- a/permissionsstandalone/src/main/AndroidManifest.xml +++ b/permissionsstandalone/src/main/AndroidManifest.xml @@ -1,5 +1,6 @@ \ No newline at end of file diff --git a/permissionsstandalone/src/main/java/foundation/e/privacymodules/permissions/PermissionsPrivacyModule.kt b/permissionsstandalone/src/main/java/foundation/e/advancedprivacy/permissions/externalinterfaces/PermissionsPrivacyModule.kt similarity index 88% rename from permissionsstandalone/src/main/java/foundation/e/privacymodules/permissions/PermissionsPrivacyModule.kt rename to permissionsstandalone/src/main/java/foundation/e/advancedprivacy/permissions/externalinterfaces/PermissionsPrivacyModule.kt index 283b417f..95f5ff09 100644 --- a/permissionsstandalone/src/main/java/foundation/e/privacymodules/permissions/PermissionsPrivacyModule.kt +++ b/permissionsstandalone/src/main/java/foundation/e/advancedprivacy/permissions/externalinterfaces/PermissionsPrivacyModule.kt @@ -15,15 +15,16 @@ * along with this program. If not, see . */ -package foundation.e.privacymodules.permissions +package foundation.e.advancedprivacy.permissions.externalinterfaces import android.app.NotificationChannel import android.content.Context import android.content.pm.PackageInfo import android.content.pm.PackageManager import android.graphics.drawable.Drawable -import foundation.e.privacymodules.permissions.data.AppOpModes -import foundation.e.privacymodules.permissions.data.ApplicationDescription +import foundation.e.advancedprivacy.domain.entities.AppOpModes +import foundation.e.advancedprivacy.domain.entities.ApplicationDescription +import foundation.e.advancedprivacy.externalinterfaces.permissions.APermissionsPrivacyModule /** * Implements [IPermissionsPrivacyModule] using only API authorized on the PlayStore. diff --git a/trackers/src/main/AndroidManifest.xml b/trackers/src/main/AndroidManifest.xml index debdf61b..615d3106 100644 --- a/trackers/src/main/AndroidManifest.xml +++ b/trackers/src/main/AndroidManifest.xml @@ -1,5 +1,6 @@ + package="foundation.e.advancedprivacy.trackers"> @@ -29,7 +30,7 @@ diff --git a/trackers/src/main/java/foundation/e/privacymodules/trackers/api/Tracker.kt b/trackers/src/main/java/foundation/e/advancedprivacy/trackers/domain/entities/Tracker.kt similarity index 93% rename from trackers/src/main/java/foundation/e/privacymodules/trackers/api/Tracker.kt rename to trackers/src/main/java/foundation/e/advancedprivacy/trackers/domain/entities/Tracker.kt index 2da5b162..5c31294e 100644 --- a/trackers/src/main/java/foundation/e/privacymodules/trackers/api/Tracker.kt +++ b/trackers/src/main/java/foundation/e/advancedprivacy/trackers/domain/entities/Tracker.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package foundation.e.privacymodules.trackers.api +package foundation.e.advancedprivacy.trackers.domain.entities /** * Describe a tracker. diff --git a/trackers/src/main/java/foundation/e/privacymodules/trackers/ForegroundStarter.kt b/trackers/src/main/java/foundation/e/advancedprivacy/trackers/services/ForegroundStarter.kt similarity index 96% rename from trackers/src/main/java/foundation/e/privacymodules/trackers/ForegroundStarter.kt rename to trackers/src/main/java/foundation/e/advancedprivacy/trackers/services/ForegroundStarter.kt index 69b4f288..a0cea433 100644 --- a/trackers/src/main/java/foundation/e/privacymodules/trackers/ForegroundStarter.kt +++ b/trackers/src/main/java/foundation/e/advancedprivacy/trackers/services/ForegroundStarter.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package foundation.e.privacymodules.trackers +package foundation.e.advancedprivacy.trackers.services import android.app.Notification import android.app.NotificationChannel -- GitLab From d7aefaba5063cdfd05c029ec4bcfba2429f8bf10 Mon Sep 17 00:00:00 2001 From: Guillaume Jacquart Date: Wed, 16 Aug 2023 09:37:47 +0200 Subject: [PATCH 2/5] Simplify interfaces and move tracker update to tracker module. --- .../data/repositories/TrackersRepository.kt | 133 ------------------ .../usecases/IpScramblingStateUseCase.kt | 24 ++-- .../domain/usecases/TrackersStateUseCase.kt | 61 +++----- .../usecases/TrackersStatisticsUseCase.kt | 115 ++++++++------- .../domain/usecases/UpdateWidgetUseCase.kt | 33 ----- .../data/repositories/AppListsRepository.kt | 29 +--- .../fakelocation/IFakeLocationModule.kt | 41 ------ .../ipscrambler/IpScramblerModule.kt | 41 +++--- .../ipscrambler/IIpScramblerModule.kt | 54 ------- privacymodule-api/consumer-rules.pro | 0 .../e/privacymodules/trackers/IDNSBlocker.kt | 26 ---- .../trackers/data/ETrackersResponse.kt | 10 ++ .../data/RemoteTrackersListRepository.kt | 61 ++++++++ .../trackers/data/StatsDatabase.kt | 22 +-- .../trackers/data/TrackersRepository.kt | 109 ++++++++++++++ .../trackers/data/WhitelistRepository.kt | 46 +++--- .../domain/usecases}/DNSBlockerRunnable.kt | 13 +- .../domain/usecases/StatisticsUseCase.kt} | 62 ++++---- .../domain/usecases}/TrackersLogger.kt | 19 +-- .../usecases/UpdateTrackerListUseCase.kt | 29 ++++ .../trackers/services}/DNSBlockerService.kt | 27 +--- .../services}/UpdateTrackersWorker.kt | 9 +- .../api/BlockTrackersPrivacyModule.kt | 98 ------------- .../api/IBlockTrackersPrivacyModule.kt | 98 ------------- .../api/ITrackTrackersPrivacyModule.kt | 110 --------------- .../api/TrackTrackersPrivacyModule.kt | 126 ----------------- .../trackers/data/TrackersRepository.kt | 57 -------- 27 files changed, 410 insertions(+), 1043 deletions(-) delete mode 100644 app/src/main/java/foundation/e/advancedprivacy/data/repositories/TrackersRepository.kt delete mode 100644 app/src/main/java/foundation/e/advancedprivacy/domain/usecases/UpdateWidgetUseCase.kt rename {app => core}/src/main/java/foundation/e/advancedprivacy/data/repositories/AppListsRepository.kt (90%) delete mode 100644 fakelocation/src/main/java/foundation/e/privacymodules/fakelocation/IFakeLocationModule.kt rename ipscrambling/src/main/java/foundation/e/{privacymodules => advancedprivacy}/ipscrambler/IpScramblerModule.kt (92%) delete mode 100644 ipscrambling/src/main/java/foundation/e/privacymodules/ipscrambler/IIpScramblerModule.kt delete mode 100644 privacymodule-api/consumer-rules.pro delete mode 100644 privacymodule-api/src/main/java/foundation/e/privacymodules/trackers/IDNSBlocker.kt create mode 100644 trackers/src/main/java/foundation/e/advancedprivacy/trackers/data/ETrackersResponse.kt create mode 100644 trackers/src/main/java/foundation/e/advancedprivacy/trackers/data/RemoteTrackersListRepository.kt rename trackers/src/main/java/foundation/e/{privacymodules => advancedprivacy}/trackers/data/StatsDatabase.kt (95%) create mode 100644 trackers/src/main/java/foundation/e/advancedprivacy/trackers/data/TrackersRepository.kt rename trackers/src/main/java/foundation/e/{privacymodules => advancedprivacy}/trackers/data/WhitelistRepository.kt (82%) rename trackers/src/main/java/foundation/e/{privacymodules/trackers => advancedprivacy/trackers/domain/usecases}/DNSBlockerRunnable.kt (92%) rename trackers/src/main/java/foundation/e/{privacymodules/trackers/data/StatsRepository.kt => advancedprivacy/trackers/domain/usecases/StatisticsUseCase.kt} (63%) rename trackers/src/main/java/foundation/e/{privacymodules/trackers => advancedprivacy/trackers/domain/usecases}/TrackersLogger.kt (78%) create mode 100644 trackers/src/main/java/foundation/e/advancedprivacy/trackers/domain/usecases/UpdateTrackerListUseCase.kt rename trackers/src/main/java/foundation/e/{privacymodules/trackers => advancedprivacy/trackers/services}/DNSBlockerService.kt (69%) rename {app/src/main/java/foundation/e/advancedprivacy => trackers/src/main/java/foundation/e/advancedprivacy/trackers/services}/UpdateTrackersWorker.kt (84%) delete mode 100644 trackers/src/main/java/foundation/e/privacymodules/trackers/api/BlockTrackersPrivacyModule.kt delete mode 100644 trackers/src/main/java/foundation/e/privacymodules/trackers/api/IBlockTrackersPrivacyModule.kt delete mode 100644 trackers/src/main/java/foundation/e/privacymodules/trackers/api/ITrackTrackersPrivacyModule.kt delete mode 100644 trackers/src/main/java/foundation/e/privacymodules/trackers/api/TrackTrackersPrivacyModule.kt delete mode 100644 trackers/src/main/java/foundation/e/privacymodules/trackers/data/TrackersRepository.kt diff --git a/app/src/main/java/foundation/e/advancedprivacy/data/repositories/TrackersRepository.kt b/app/src/main/java/foundation/e/advancedprivacy/data/repositories/TrackersRepository.kt deleted file mode 100644 index 568d76b9..00000000 --- a/app/src/main/java/foundation/e/advancedprivacy/data/repositories/TrackersRepository.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.data.repositories - -import android.content.Context -import com.google.gson.Gson -import foundation.e.privacymodules.trackers.api.Tracker -import retrofit2.Retrofit -import retrofit2.converter.scalars.ScalarsConverterFactory -import retrofit2.http.GET -import timber.log.Timber -import java.io.File -import java.io.FileInputStream -import java.io.FileWriter -import java.io.IOException -import java.io.InputStreamReader -import java.io.PrintWriter - -class TrackersRepository(private val context: Context) { - - private val eTrackerFileName = "e_trackers.json" - private val eTrackerFile = File(context.filesDir.absolutePath, eTrackerFileName) - - var trackers: List = emptyList() - private set - - init { - initTrackersFile() - } - - suspend fun update() { - val api = ETrackersApi.build() - try { - saveData(eTrackerFile, api.trackers()) - initTrackersFile() - } catch (e: Exception) { - Timber.e("While updating trackers", e) - } - } - - private fun initTrackersFile() { - try { - var inputStream = context.assets.open(eTrackerFileName) - if (eTrackerFile.exists()) { - inputStream = FileInputStream(eTrackerFile) - } - val reader = InputStreamReader(inputStream, "UTF-8") - val trackerResponse = - Gson().fromJson(reader, ETrackersApi.ETrackersResponse::class.java) - - trackers = mapper(trackerResponse) - - reader.close() - inputStream.close() - } catch (e: Exception) { - Timber.e("While parsing trackers in assets", e) - } - } - - private fun mapper(response: ETrackersApi.ETrackersResponse): List { - return response.trackers.mapNotNull { - try { - it.toTracker() - } catch (e: Exception) { - null - } - } - } - - private fun ETrackersApi.ETrackersResponse.ETracker.toTracker(): Tracker { - return Tracker( - id = id!!, - hostnames = hostnames!!.toSet(), - label = name!!, - exodusId = exodusId - ) - } - - private fun saveData(file: File, data: String): Boolean { - try { - val fos = FileWriter(file, false) - val ps = PrintWriter(fos) - ps.apply { - print(data) - flush() - close() - } - return true - } catch (e: IOException) { - e.printStackTrace() - } - return false - } -} - -interface ETrackersApi { - companion object { - fun build(): ETrackersApi { - val retrofit = Retrofit.Builder() - .baseUrl("https://gitlab.e.foundation/e/os/tracker-list/-/raw/main/") - .addConverterFactory(ScalarsConverterFactory.create()) - .build() - return retrofit.create(ETrackersApi::class.java) - } - } - - @GET("list/e_trackers.json") - suspend fun trackers(): String - - data class ETrackersResponse(val trackers: List) { - data class ETracker( - val id: String?, - val hostnames: List?, - val name: String?, - val exodusId: String? - ) - } -} 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 70607cf6..a7ed660b 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 @@ -19,14 +19,14 @@ package foundation.e.advancedprivacy.domain.usecases import foundation.e.advancedprivacy.data.repositories.AppListsRepository import foundation.e.advancedprivacy.data.repositories.LocalStateRepository +import foundation.e.advancedprivacy.domain.entities.ApplicationDescription import foundation.e.advancedprivacy.domain.entities.InternetPrivacyMode import foundation.e.advancedprivacy.domain.entities.InternetPrivacyMode.HIDE_IP import foundation.e.advancedprivacy.domain.entities.InternetPrivacyMode.HIDE_IP_LOADING import foundation.e.advancedprivacy.domain.entities.InternetPrivacyMode.REAL_IP import foundation.e.advancedprivacy.domain.entities.InternetPrivacyMode.REAL_IP_LOADING -import foundation.e.privacymodules.ipscrambler.IIpScramblerModule -import foundation.e.privacymodules.permissions.IPermissionsPrivacyModule -import foundation.e.privacymodules.permissions.data.ApplicationDescription +import foundation.e.advancedprivacy.externalinterfaces.permissions.IPermissionsPrivacyModule +import foundation.e.advancedprivacy.ipscrambler.IpScramblerModule import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.channels.awaitClose @@ -38,7 +38,7 @@ import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch class IpScramblingStateUseCase( - private val ipScramblerModule: IIpScramblerModule, + private val ipScramblerModule: IpScramblerModule, private val permissionsPrivacyModule: IPermissionsPrivacyModule, private val appDesc: ApplicationDescription, private val localStateRepository: LocalStateRepository, @@ -46,8 +46,8 @@ class IpScramblingStateUseCase( private val coroutineScope: CoroutineScope ) { val internetPrivacyMode: StateFlow = callbackFlow { - val listener = object : IIpScramblerModule.Listener { - override fun onStatusChanged(newStatus: IIpScramblerModule.Status) { + val listener = object : IpScramblerModule.Listener { + override fun onStatusChanged(newStatus: IpScramblerModule.Status) { trySend(map(newStatus)) } @@ -169,13 +169,13 @@ class IpScramblingStateUseCase( } } - private fun map(status: IIpScramblerModule.Status): InternetPrivacyMode { + private fun map(status: IpScramblerModule.Status): InternetPrivacyMode { return when (status) { - IIpScramblerModule.Status.OFF -> REAL_IP - IIpScramblerModule.Status.ON -> HIDE_IP - IIpScramblerModule.Status.STARTING -> HIDE_IP_LOADING - IIpScramblerModule.Status.STOPPING, - IIpScramblerModule.Status.START_DISABLED -> REAL_IP_LOADING + IpScramblerModule.Status.OFF -> REAL_IP + IpScramblerModule.Status.ON -> HIDE_IP + IpScramblerModule.Status.STARTING -> HIDE_IP_LOADING + IpScramblerModule.Status.STOPPING, + IpScramblerModule.Status.START_DISABLED -> REAL_IP_LOADING } } } diff --git a/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/TrackersStateUseCase.kt b/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/TrackersStateUseCase.kt index 882d53f7..ed15a414 100644 --- a/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/TrackersStateUseCase.kt +++ b/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/TrackersStateUseCase.kt @@ -19,87 +19,68 @@ package foundation.e.advancedprivacy.domain.usecases import foundation.e.advancedprivacy.data.repositories.AppListsRepository import foundation.e.advancedprivacy.data.repositories.LocalStateRepository -import foundation.e.advancedprivacy.data.repositories.TrackersRepository -import foundation.e.privacymodules.permissions.data.ApplicationDescription -import foundation.e.privacymodules.trackers.api.IBlockTrackersPrivacyModule -import foundation.e.privacymodules.trackers.api.ITrackTrackersPrivacyModule -import foundation.e.privacymodules.trackers.api.Tracker +import foundation.e.advancedprivacy.domain.entities.ApplicationDescription +import foundation.e.advancedprivacy.trackers.data.WhitelistRepository +import foundation.e.advancedprivacy.trackers.domain.entities.Tracker import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch class TrackersStateUseCase( - private val blockTrackersPrivacyModule: IBlockTrackersPrivacyModule, - private val trackersPrivacyModule: ITrackTrackersPrivacyModule, + private val whitelistRepository: WhitelistRepository, private val localStateRepository: LocalStateRepository, - private val trackersRepository: TrackersRepository, private val appListsRepository: AppListsRepository, - private val coroutineScope: CoroutineScope + coroutineScope: CoroutineScope ) { init { - trackersPrivacyModule.start( - trackers = trackersRepository.trackers, - getAppByAPId = appListsRepository::getApp, - getAppByUid = appListsRepository::getApp, - enableNotification = false - ) coroutineScope.launch { localStateRepository.blockTrackers.collect { enabled -> - if (enabled) { - blockTrackersPrivacyModule.enableBlocking() - } else { - blockTrackersPrivacyModule.disableBlocking() - } + whitelistRepository.isBlockingEnabled = enabled updateAllTrackersBlockedState() } } } private fun updateAllTrackersBlockedState() { - localStateRepository.areAllTrackersBlocked.value = blockTrackersPrivacyModule.isBlockingEnabled() && - blockTrackersPrivacyModule.isWhiteListEmpty() + localStateRepository.areAllTrackersBlocked.value = whitelistRepository.isBlockingEnabled && + whitelistRepository.areWhiteListEmpty() } fun isWhitelisted(app: ApplicationDescription): Boolean { - return isWhitelisted(app, appListsRepository, blockTrackersPrivacyModule) + return isWhitelisted(app, appListsRepository, whitelistRepository) } fun toggleAppWhitelist(app: ApplicationDescription, isWhitelisted: Boolean) { appListsRepository.applyForHiddenApps(app) { - blockTrackersPrivacyModule.setWhiteListed(it, isWhitelisted) + whitelistRepository.setWhiteListed(it.apId, isWhitelisted) } updateAllTrackersBlockedState() } fun blockTracker(app: ApplicationDescription, tracker: Tracker, isBlocked: Boolean) { appListsRepository.applyForHiddenApps(app) { - blockTrackersPrivacyModule.setWhiteListed(tracker, it, !isBlocked) + whitelistRepository.setWhiteListed(tracker, it.apId, !isBlocked) } updateAllTrackersBlockedState() } fun clearWhitelist(app: ApplicationDescription) { appListsRepository.applyForHiddenApps( - app, - blockTrackersPrivacyModule::clearWhiteList - ) + app + ) { + whitelistRepository.clearWhiteList(it.apId) + } updateAllTrackersBlockedState() } - - fun updateTrackers() = coroutineScope.launch { - trackersRepository.update() - trackersPrivacyModule.start( - trackers = trackersRepository.trackers, - getAppByAPId = appListsRepository::getApp, - getAppByUid = appListsRepository::getApp, - enableNotification = false - ) - } } fun isWhitelisted( app: ApplicationDescription, appListsRepository: AppListsRepository, - blockTrackersPrivacyModule: IBlockTrackersPrivacyModule + whitelistRepository: WhitelistRepository + ): Boolean { - return appListsRepository.anyForHiddenApps(app, blockTrackersPrivacyModule::isWhitelisted) + return appListsRepository.anyForHiddenApps( + app, + whitelistRepository::isAppWhiteListed + ) } 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 43e44964..b0c9f391 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 @@ -22,15 +22,14 @@ import foundation.e.advancedprivacy.R import foundation.e.advancedprivacy.common.throttleFirst import foundation.e.advancedprivacy.data.repositories.AppListsRepository import foundation.e.advancedprivacy.domain.entities.AppWithCounts +import foundation.e.advancedprivacy.domain.entities.ApplicationDescription import foundation.e.advancedprivacy.domain.entities.TrackersPeriodicStatistics -import foundation.e.privacymodules.permissions.data.ApplicationDescription -import foundation.e.privacymodules.trackers.api.IBlockTrackersPrivacyModule -import foundation.e.privacymodules.trackers.api.ITrackTrackersPrivacyModule -import foundation.e.privacymodules.trackers.api.Tracker +import foundation.e.advancedprivacy.trackers.data.TrackersRepository +import foundation.e.advancedprivacy.trackers.data.WhitelistRepository +import foundation.e.advancedprivacy.trackers.domain.entities.Tracker +import foundation.e.advancedprivacy.trackers.domain.usecases.StatisticsUseCase import kotlinx.coroutines.FlowPreview -import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onStart @@ -41,8 +40,9 @@ import kotlin.time.Duration import kotlin.time.Duration.Companion.seconds class TrackersStatisticsUseCase( - private val trackTrackersPrivacyModule: ITrackTrackersPrivacyModule, - private val blockTrackersPrivacyModule: IBlockTrackersPrivacyModule, + private val statisticsUseCase: StatisticsUseCase, + private val whitelistRepository: WhitelistRepository, + private val trackersRepository: TrackersRepository, private val appListsRepository: AppListsRepository, private val resources: Resources ) { @@ -50,54 +50,45 @@ class TrackersStatisticsUseCase( appListsRepository.apps() } - private fun rawUpdates(): Flow = callbackFlow { - val listener = object : ITrackTrackersPrivacyModule.Listener { - override fun onNewData() { - trySend(Unit) - } - } - trackTrackersPrivacyModule.addListener(listener) - awaitClose { trackTrackersPrivacyModule.removeListener(listener) } - } - @OptIn(FlowPreview::class) - fun listenUpdates(debounce: Duration = 1.seconds) = rawUpdates() - .throttleFirst(windowDuration = debounce) - .onStart { emit(Unit) } + fun listenUpdates(debounce: Duration = 1.seconds) = + statisticsUseCase.newDataAvailable + .throttleFirst(windowDuration = debounce) + .onStart { emit(Unit) } fun getDayStatistics(): Pair { return TrackersPeriodicStatistics( - callsBlockedNLeaked = trackTrackersPrivacyModule.getPastDayTrackersCalls(), + callsBlockedNLeaked = statisticsUseCase.getTrackersCallsOnPeriod(24, ChronoUnit.HOURS), periods = buildDayLabels(), - trackersCount = trackTrackersPrivacyModule.getPastDayTrackersCount(), + trackersCount = statisticsUseCase.getActiveTrackersByPeriod(24, ChronoUnit.HOURS), graduations = buildDayGraduations(), - ) to trackTrackersPrivacyModule.getTrackersCount() + ) to statisticsUseCase.getContactedTrackersCount() } fun getNonBlockedTrackersCount(): Flow { - return if (blockTrackersPrivacyModule.isBlockingEnabled()) + return if (whitelistRepository.isBlockingEnabled) appListsRepository.allApps().map { apps -> val whiteListedTrackers = mutableSetOf() - val whiteListedApps = blockTrackersPrivacyModule.getWhiteListedApp() + val whiteListedApps = whitelistRepository.getWhiteListedApp() apps.forEach { app -> if (app in whiteListedApps) { - whiteListedTrackers.addAll(trackTrackersPrivacyModule.getTrackersForApp(app)) + whiteListedTrackers.addAll(statisticsUseCase.getTrackers(listOf(app))) } else { - whiteListedTrackers.addAll(blockTrackersPrivacyModule.getWhiteList(app)) + whiteListedTrackers.addAll(getWhiteList(app)) } } whiteListedTrackers.size } - else flowOf(trackTrackersPrivacyModule.getTrackersCount()) + else flowOf(statisticsUseCase.getContactedTrackersCount()) } fun getMostLeakedApp(): ApplicationDescription? { - return trackTrackersPrivacyModule.getPastDayMostLeakedApp() + return statisticsUseCase.getMostLeakedApp(24, ChronoUnit.HOURS) } - fun getDayTrackersCalls() = trackTrackersPrivacyModule.getPastDayTrackersCalls() + fun getDayTrackersCalls() = statisticsUseCase.getTrackersCallsOnPeriod(24, ChronoUnit.HOURS) - fun getDayTrackersCount() = trackTrackersPrivacyModule.getPastDayTrackersCount() + fun getDayTrackersCount() = statisticsUseCase.getActiveTrackersByPeriod(24, ChronoUnit.HOURS) private fun buildDayGraduations(): List { val formatter = DateTimeFormatter.ofPattern( @@ -155,25 +146,23 @@ class TrackersStatisticsUseCase( } fun getDayMonthYearStatistics(): Triple { - return with(trackTrackersPrivacyModule) { - Triple( - TrackersPeriodicStatistics( - callsBlockedNLeaked = getPastDayTrackersCalls(), - periods = buildDayLabels(), - trackersCount = getPastDayTrackersCount() - ), - TrackersPeriodicStatistics( - callsBlockedNLeaked = getPastMonthTrackersCalls(), - periods = buildMonthLabels(), - trackersCount = getPastMonthTrackersCount() - ), - TrackersPeriodicStatistics( - callsBlockedNLeaked = getPastYearTrackersCalls(), - periods = buildYearLabels(), - trackersCount = getPastYearTrackersCount() - ) + return Triple( + TrackersPeriodicStatistics( + callsBlockedNLeaked = statisticsUseCase.getTrackersCallsOnPeriod(24, ChronoUnit.HOURS), + periods = buildDayLabels(), + trackersCount = statisticsUseCase.getActiveTrackersByPeriod(24, ChronoUnit.HOURS) + ), + TrackersPeriodicStatistics( + callsBlockedNLeaked = statisticsUseCase.getTrackersCallsOnPeriod(30, ChronoUnit.DAYS), + periods = buildMonthLabels(), + trackersCount = statisticsUseCase.getActiveTrackersByPeriod(30, ChronoUnit.DAYS) + ), + TrackersPeriodicStatistics( + callsBlockedNLeaked = statisticsUseCase.getTrackersCallsOnPeriod(12, ChronoUnit.MONTHS), + periods = buildYearLabels(), + trackersCount = statisticsUseCase.getActiveTrackersByPeriod(12, ChronoUnit.MONTHS) ) - } + ) } fun getTrackersWithWhiteList(app: ApplicationDescription): List> { @@ -181,8 +170,8 @@ class TrackersStatisticsUseCase( app = app, map = { appDesc: ApplicationDescription -> ( - trackTrackersPrivacyModule.getTrackersForApp(appDesc) to - blockTrackersPrivacyModule.getWhiteList(appDesc) + statisticsUseCase.getTrackers(listOf(appDesc)) to + getWhiteList(appDesc) ) }, reduce = { lists -> @@ -200,7 +189,7 @@ class TrackersStatisticsUseCase( return appListsRepository.mapReduceForHiddenApps( app = app, map = { appDesc: ApplicationDescription -> - blockTrackersPrivacyModule.getWhiteList(appDesc).isEmpty() + getWhiteList(appDesc).isEmpty() }, reduce = { areEmpty -> areEmpty.all { it } } ) @@ -209,7 +198,9 @@ class TrackersStatisticsUseCase( fun getCalls(app: ApplicationDescription): Pair { return appListsRepository.mapReduceForHiddenApps( app = app, - map = trackTrackersPrivacyModule::getPastDayTrackersCallsForApp, + map = { + statisticsUseCase.getCalls(it, 24, ChronoUnit.HOURS) + }, reduce = { zip -> zip.unzip().let { (blocked, leaked) -> blocked.sum() to leaked.sum() @@ -219,7 +210,7 @@ class TrackersStatisticsUseCase( } fun getAppsWithCounts(): Flow> { - val trackersCounts = trackTrackersPrivacyModule.getTrackersCountByApp() + val trackersCounts = statisticsUseCase.getContactedTrackersCountByApp() val hiddenAppsTrackersWithWhiteList = getTrackersWithWhiteList(appListsRepository.dummySystemApp) val acAppsTrackersWithWhiteList = @@ -227,7 +218,7 @@ class TrackersStatisticsUseCase( return appListsRepository.apps() .map { apps -> - val callsByApp = trackTrackersPrivacyModule.getPastDayTrackersCallsByApps() + val callsByApp = statisticsUseCase.getCallsByApps(24, ChronoUnit.HOURS) apps.map { app -> val calls = appListsRepository.mapReduceForHiddenApps( app = app, @@ -241,8 +232,8 @@ class TrackersStatisticsUseCase( AppWithCounts( app = app, - isWhitelisted = !blockTrackersPrivacyModule.isBlockingEnabled() || - isWhitelisted(app, appListsRepository, blockTrackersPrivacyModule), + isWhitelisted = !whitelistRepository.isBlockingEnabled || + isWhitelisted(app, appListsRepository, whitelistRepository), trackersCount = when (app) { appListsRepository.dummySystemApp -> hiddenAppsTrackersWithWhiteList.size @@ -256,7 +247,7 @@ class TrackersStatisticsUseCase( appListsRepository.dummyCompatibilityApp -> acAppsTrackersWithWhiteList.count { it.second } else -> - blockTrackersPrivacyModule.getWhiteList(app).size + getWhiteList(app).size }, blockedLeaks = calls.first, leaks = calls.second @@ -266,6 +257,12 @@ class TrackersStatisticsUseCase( } } + private fun getWhiteList(app: ApplicationDescription): List { + return whitelistRepository.getWhiteListForApp(app).mapNotNull { + trackersRepository.getTracker(it) + } + } + private val mostLeakedAppsComparator: Comparator = Comparator { o1, o2 -> val leaks = o2.leaks - o1.leaks if (leaks != 0) leaks else { diff --git a/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/UpdateWidgetUseCase.kt b/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/UpdateWidgetUseCase.kt deleted file mode 100644 index 94c734c4..00000000 --- a/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/UpdateWidgetUseCase.kt +++ /dev/null @@ -1,33 +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.domain.usecases - -import foundation.e.advancedprivacy.data.repositories.LocalStateRepository -import foundation.e.privacymodules.trackers.api.ITrackTrackersPrivacyModule - -class UpdateWidgetUseCase( - private val localStateRepository: LocalStateRepository, - private val trackTrackersPrivacyModule: ITrackTrackersPrivacyModule, -) { - init { - trackTrackersPrivacyModule.addListener(object : ITrackTrackersPrivacyModule.Listener { - override fun onNewData() { - } - }) - } -} diff --git a/app/src/main/java/foundation/e/advancedprivacy/data/repositories/AppListsRepository.kt b/core/src/main/java/foundation/e/advancedprivacy/data/repositories/AppListsRepository.kt similarity index 90% rename from app/src/main/java/foundation/e/advancedprivacy/data/repositories/AppListsRepository.kt rename to core/src/main/java/foundation/e/advancedprivacy/data/repositories/AppListsRepository.kt index 2d7651d1..f29bb8a1 100644 --- a/app/src/main/java/foundation/e/advancedprivacy/data/repositories/AppListsRepository.kt +++ b/core/src/main/java/foundation/e/advancedprivacy/data/repositories/AppListsRepository.kt @@ -22,10 +22,9 @@ import android.content.Context import android.content.Intent import android.content.pm.ApplicationInfo import android.content.pm.PackageInfo -import foundation.e.advancedprivacy.R -import foundation.e.privacymodules.permissions.PermissionsPrivacyModule -import foundation.e.privacymodules.permissions.data.ApplicationDescription -import foundation.e.privacymodules.permissions.data.ProfileType +import foundation.e.advancedprivacy.domain.entities.ApplicationDescription +import foundation.e.advancedprivacy.domain.entities.ProfileType +import foundation.e.advancedprivacy.externalinterfaces.permissions.IPermissionsPrivacyModule import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job @@ -36,7 +35,9 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking class AppListsRepository( - private val permissionsModule: PermissionsPrivacyModule, + private val permissionsModule: IPermissionsPrivacyModule, + val dummySystemApp: ApplicationDescription, + val dummyCompatibilityApp: ApplicationDescription, private val context: Context, private val coroutineScope: CoroutineScope ) { @@ -51,24 +52,6 @@ class AppListsRepository( ) } - val dummySystemApp = ApplicationDescription( - packageName = "foundation.e.dummysystemapp", - uid = -1, - label = context.getString(R.string.dummy_system_app_label), - icon = context.getDrawable(R.drawable.ic_e_app_logo), - profileId = -1, - profileType = ProfileType.MAIN - ) - - val dummyCompatibilityApp = ApplicationDescription( - packageName = "foundation.e.dummyappscompatibilityapp", - uid = -2, - label = context.getString(R.string.dummy_apps_compatibility_app_label), - icon = context.getDrawable(R.drawable.ic_apps_compatibility_components), - profileId = -1, - profileType = ProfileType.MAIN - ) - private suspend fun fetchAppDescriptions(fetchMissingIcons: Boolean = false) { val launcherPackageNames = context.packageManager.queryIntentActivities( Intent(Intent.ACTION_MAIN, null).apply { addCategory(Intent.CATEGORY_LAUNCHER) }, diff --git a/fakelocation/src/main/java/foundation/e/privacymodules/fakelocation/IFakeLocationModule.kt b/fakelocation/src/main/java/foundation/e/privacymodules/fakelocation/IFakeLocationModule.kt deleted file mode 100644 index 32906f82..00000000 --- a/fakelocation/src/main/java/foundation/e/privacymodules/fakelocation/IFakeLocationModule.kt +++ /dev/null @@ -1,41 +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.privacymodules.fakelocation - -/** - * Manage a fake location on the device. - */ -interface IFakeLocationModule { - /** - * Start to fake the location module. Call [setFakeLocation] after to set the fake - * position. - */ - fun startFakeLocation() - - /** - * Set or update the faked position. - * @param latitude the latitude of the fake position in degrees. - * @param longitude the longitude of the fake position in degrees. - */ - fun setFakeLocation(latitude: Double, longitude: Double) - - /** - * Stop the fake location module, giving back hand to the true location modules. - */ - fun stopFakeLocation() -} diff --git a/ipscrambling/src/main/java/foundation/e/privacymodules/ipscrambler/IpScramblerModule.kt b/ipscrambling/src/main/java/foundation/e/advancedprivacy/ipscrambler/IpScramblerModule.kt similarity index 92% rename from ipscrambling/src/main/java/foundation/e/privacymodules/ipscrambler/IpScramblerModule.kt rename to ipscrambling/src/main/java/foundation/e/advancedprivacy/ipscrambler/IpScramblerModule.kt index 1c393304..d1f01a03 100644 --- a/ipscrambling/src/main/java/foundation/e/privacymodules/ipscrambler/IpScramblerModule.kt +++ b/ipscrambling/src/main/java/foundation/e/advancedprivacy/ipscrambler/IpScramblerModule.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package foundation.e.privacymodules.ipscrambler +package foundation.e.advancedprivacy.ipscrambler import android.annotation.SuppressLint import android.content.BroadcastReceiver @@ -29,8 +29,6 @@ import android.os.Looper import android.os.Message import android.util.Log import androidx.localbroadcastmanager.content.LocalBroadcastManager -import foundation.e.privacymodules.ipscrambler.IIpScramblerModule.Listener -import foundation.e.privacymodules.ipscrambler.IIpScramblerModule.Status import org.torproject.android.service.OrbotConstants import org.torproject.android.service.OrbotConstants.ACTION_STOP_FOREGROUND_TASK import org.torproject.android.service.OrbotService @@ -38,7 +36,16 @@ import org.torproject.android.service.util.Prefs import java.security.InvalidParameterException @SuppressLint("CommitPrefEdits") -class IpScramblerModule(private val context: Context) : IIpScramblerModule { +class IpScramblerModule(private val context: Context) { + interface Listener { + fun onStatusChanged(newStatus: Status) + fun log(message: String) + fun onTrafficUpdate(upload: Long, download: Long, read: Long, write: Long) + } + + enum class Status { + OFF, ON, STARTING, STOPPING, START_DISABLED + } companion object { const val TAG = "IpScramblerModule" @@ -221,11 +228,11 @@ class IpScramblerModule(private val context: Context) : IIpScramblerModule { return if (raw.isEmpty()) raw else raw.slice(1..2) } - override fun prepareAndroidVpn(): Intent? { + fun prepareAndroidVpn(): Intent? { return VpnService.prepare(context) } - override fun start(enableNotification: Boolean) { + fun start(enableNotification: Boolean) { Prefs.enableNotification(enableNotification) Prefs.putUseVpn(true) Prefs.putStartOnBoot(true) @@ -234,7 +241,7 @@ class IpScramblerModule(private val context: Context) : IIpScramblerModule { sendIntentToService(OrbotConstants.ACTION_START_VPN) } - override fun stop() { + fun stop() { updateStatus(Status.STOPPING) Prefs.putUseVpn(false) @@ -261,7 +268,7 @@ class IpScramblerModule(private val context: Context) : IIpScramblerModule { ) } - override fun requestStatus() { + fun requestStatus() { if (isServiceRunning()) { sendIntentToService(OrbotConstants.ACTION_STATUS) } else { @@ -269,33 +276,33 @@ class IpScramblerModule(private val context: Context) : IIpScramblerModule { } } - override var appList: Set + var appList: Set get() = getTorifiedApps() set(value) = saveTorifiedApps(value) - override var exitCountry: String + var exitCountry: String get() = getExitCountryCode() set(value) = setExitCountryCode(value) - override fun getAvailablesLocations(): Set = EXIT_COUNTRY_CODES + fun getAvailablesLocations(): Set = EXIT_COUNTRY_CODES - override var httpProxyPort: Int = -1 + var httpProxyPort: Int = -1 private set - override var socksProxyPort: Int = -1 + var socksProxyPort: Int = -1 private set - override fun addListener(listener: Listener) { + fun addListener(listener: Listener) { listeners.add(listener) } - override fun removeListener(listener: Listener) { + fun removeListener(listener: Listener) { listeners.remove(listener) } - override fun clearListeners() { + fun clearListeners() { listeners.clear() } - override fun onCleared() { + fun onCleared() { LocalBroadcastManager.getInstance(context).unregisterReceiver(localBroadcastReceiver) } } diff --git a/ipscrambling/src/main/java/foundation/e/privacymodules/ipscrambler/IIpScramblerModule.kt b/ipscrambling/src/main/java/foundation/e/privacymodules/ipscrambler/IIpScramblerModule.kt deleted file mode 100644 index 859319a5..00000000 --- a/ipscrambling/src/main/java/foundation/e/privacymodules/ipscrambler/IIpScramblerModule.kt +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2021 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.privacymodules.ipscrambler - -import android.content.Intent - -interface IIpScramblerModule { - fun prepareAndroidVpn(): Intent? - - fun start(enableNotification: Boolean = true) - - fun stop() - - fun requestStatus() - - var appList: Set - - var exitCountry: String - fun getAvailablesLocations(): Set - - val httpProxyPort: Int - val socksProxyPort: Int - - fun addListener(listener: Listener) - fun removeListener(listener: Listener) - fun clearListeners() - - fun onCleared() - - interface Listener { - fun onStatusChanged(newStatus: Status) - fun log(message: String) - fun onTrafficUpdate(upload: Long, download: Long, read: Long, write: Long) - } - - enum class Status { - OFF, ON, STARTING, STOPPING, START_DISABLED - } -} diff --git a/privacymodule-api/consumer-rules.pro b/privacymodule-api/consumer-rules.pro deleted file mode 100644 index e69de29b..00000000 diff --git a/privacymodule-api/src/main/java/foundation/e/privacymodules/trackers/IDNSBlocker.kt b/privacymodule-api/src/main/java/foundation/e/privacymodules/trackers/IDNSBlocker.kt deleted file mode 100644 index a132aefa..00000000 --- a/privacymodule-api/src/main/java/foundation/e/privacymodules/trackers/IDNSBlocker.kt +++ /dev/null @@ -1,26 +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.privacymodules.trackers - -interface IDNSBlocker { - companion object { - const val DUMMY_APP_UID = -1 - } - - fun shouldBlock(hostname: String, appUid: Int): Boolean -} diff --git a/trackers/src/main/java/foundation/e/advancedprivacy/trackers/data/ETrackersResponse.kt b/trackers/src/main/java/foundation/e/advancedprivacy/trackers/data/ETrackersResponse.kt new file mode 100644 index 00000000..1b38ecf9 --- /dev/null +++ b/trackers/src/main/java/foundation/e/advancedprivacy/trackers/data/ETrackersResponse.kt @@ -0,0 +1,10 @@ +package foundation.e.advancedprivacy.trackers.data + +data class ETrackersResponse(val trackers: List) { + data class ETracker( + val id: String?, + val hostnames: List?, + val name: String?, + val exodusId: String? + ) +} diff --git a/trackers/src/main/java/foundation/e/advancedprivacy/trackers/data/RemoteTrackersListRepository.kt b/trackers/src/main/java/foundation/e/advancedprivacy/trackers/data/RemoteTrackersListRepository.kt new file mode 100644 index 00000000..c2c0768e --- /dev/null +++ b/trackers/src/main/java/foundation/e/advancedprivacy/trackers/data/RemoteTrackersListRepository.kt @@ -0,0 +1,61 @@ +/* + * 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.data.repositories + +import retrofit2.Retrofit +import retrofit2.converter.scalars.ScalarsConverterFactory +import retrofit2.http.GET +import timber.log.Timber +import java.io.File +import java.io.FileWriter +import java.io.IOException +import java.io.PrintWriter + +class RemoteTrackersListRepository { + + fun saveData(file: File, data: String): Boolean { + try { + val fos = FileWriter(file, false) + val ps = PrintWriter(fos) + ps.apply { + print(data) + flush() + close() + } + return true + } catch (e: IOException) { + Timber.e("While saving tracker file.", e) + } + return false + } +} + +interface ETrackersApi { + companion object { + fun build(): ETrackersApi { + val retrofit = Retrofit.Builder() + .baseUrl("https://gitlab.e.foundation/e/os/tracker-list/-/raw/main/") + .addConverterFactory(ScalarsConverterFactory.create()) + .build() + return retrofit.create(ETrackersApi::class.java) + } + } + + @GET("list/e_trackers.json") + suspend fun trackers(): String +} diff --git a/trackers/src/main/java/foundation/e/privacymodules/trackers/data/StatsDatabase.kt b/trackers/src/main/java/foundation/e/advancedprivacy/trackers/data/StatsDatabase.kt similarity index 95% rename from trackers/src/main/java/foundation/e/privacymodules/trackers/data/StatsDatabase.kt rename to trackers/src/main/java/foundation/e/advancedprivacy/trackers/data/StatsDatabase.kt index 4d287d45..6aa76cfd 100644 --- a/trackers/src/main/java/foundation/e/privacymodules/trackers/data/StatsDatabase.kt +++ b/trackers/src/main/java/foundation/e/advancedprivacy/trackers/data/StatsDatabase.kt @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -package foundation.e.privacymodules.trackers.data +package foundation.e.advancedprivacy.trackers.data import android.content.ContentValues import android.content.Context @@ -25,13 +25,13 @@ import android.database.sqlite.SQLiteDatabase import android.database.sqlite.SQLiteOpenHelper import android.provider.BaseColumns import androidx.core.database.getStringOrNull -import foundation.e.privacymodules.trackers.api.Tracker -import foundation.e.privacymodules.trackers.data.StatsDatabase.AppTrackerEntry.COLUMN_NAME_APPID -import foundation.e.privacymodules.trackers.data.StatsDatabase.AppTrackerEntry.COLUMN_NAME_NUMBER_BLOCKED -import foundation.e.privacymodules.trackers.data.StatsDatabase.AppTrackerEntry.COLUMN_NAME_NUMBER_CONTACTED -import foundation.e.privacymodules.trackers.data.StatsDatabase.AppTrackerEntry.COLUMN_NAME_TIMESTAMP -import foundation.e.privacymodules.trackers.data.StatsDatabase.AppTrackerEntry.COLUMN_NAME_TRACKER -import foundation.e.privacymodules.trackers.data.StatsDatabase.AppTrackerEntry.TABLE_NAME +import foundation.e.advancedprivacy.trackers.data.StatsDatabase.AppTrackerEntry.COLUMN_NAME_APPID +import foundation.e.advancedprivacy.trackers.data.StatsDatabase.AppTrackerEntry.COLUMN_NAME_NUMBER_BLOCKED +import foundation.e.advancedprivacy.trackers.data.StatsDatabase.AppTrackerEntry.COLUMN_NAME_NUMBER_CONTACTED +import foundation.e.advancedprivacy.trackers.data.StatsDatabase.AppTrackerEntry.COLUMN_NAME_TIMESTAMP +import foundation.e.advancedprivacy.trackers.data.StatsDatabase.AppTrackerEntry.COLUMN_NAME_TRACKER +import foundation.e.advancedprivacy.trackers.data.StatsDatabase.AppTrackerEntry.TABLE_NAME +import foundation.e.advancedprivacy.trackers.domain.entities.Tracker import timber.log.Timber import java.time.ZonedDateTime import java.time.format.DateTimeFormatter @@ -39,7 +39,10 @@ import java.time.temporal.ChronoUnit import java.time.temporal.TemporalUnit import java.util.concurrent.TimeUnit -class StatsDatabase(context: Context) : +class StatsDatabase( + context: Context, + private val trackersRepository: TrackersRepository +) : SQLiteOpenHelper(context, DATABASE_NAME, null, DATABASE_VERSION) { companion object { @@ -84,7 +87,6 @@ class StatsDatabase(context: Context) : ) private val lock = Any() - private val trackersRepository = TrackersRepository.getInstance() override fun onCreate(db: SQLiteDatabase) { db.execSQL(SQL_CREATE_TABLE) diff --git a/trackers/src/main/java/foundation/e/advancedprivacy/trackers/data/TrackersRepository.kt b/trackers/src/main/java/foundation/e/advancedprivacy/trackers/data/TrackersRepository.kt new file mode 100644 index 00000000..a7d5e49d --- /dev/null +++ b/trackers/src/main/java/foundation/e/advancedprivacy/trackers/data/TrackersRepository.kt @@ -0,0 +1,109 @@ +/* + * 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.trackers.data + +import android.content.Context +import com.google.gson.Gson +import foundation.e.advancedprivacy.trackers.domain.entities.Tracker +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import timber.log.Timber +import java.io.File +import java.io.FileInputStream +import java.io.InputStreamReader + +class TrackersRepository( + private val context: Context, + coroutineScope: CoroutineScope +) { + + private var trackersById: Map = HashMap() + private var hostnameToId: Map = HashMap() + + private val eTrackerFileName = "e_trackers.json" + val eTrackerFile = File(context.filesDir.absolutePath, eTrackerFileName) + + init { + coroutineScope.launch(Dispatchers.IO) { + initTrackersFile() + } + } + fun initTrackersFile() { + try { + var inputStream = context.assets.open(eTrackerFileName) + if (eTrackerFile.exists()) { + inputStream = FileInputStream(eTrackerFile) + } + val reader = InputStreamReader(inputStream, "UTF-8") + val trackerResponse = + Gson().fromJson(reader, ETrackersResponse::class.java) + + setTrackersList(mapper(trackerResponse)) + + reader.close() + inputStream.close() + } catch (e: Exception) { + Timber.e("While parsing trackers in assets", e) + } + } + + private fun mapper(response: ETrackersResponse): List { + return response.trackers.mapNotNull { + try { + it.toTracker() + } catch (e: Exception) { + null + } + } + } + + private fun ETrackersResponse.ETracker.toTracker(): Tracker { + return Tracker( + id = id!!, + hostnames = hostnames!!.toSet(), + label = name!!, + exodusId = exodusId + ) + } + + private fun setTrackersList(list: List) { + val trackersById: MutableMap = HashMap() + val hostnameToId: MutableMap = HashMap() + list.forEach { tracker -> + trackersById[tracker.id] = tracker + for (hostname in tracker.hostnames) { + hostnameToId[hostname] = tracker.id + } + } + this.trackersById = trackersById + this.hostnameToId = hostnameToId + } + + fun isTracker(hostname: String?): Boolean { + return hostnameToId.containsKey(hostname) + } + + fun getTrackerId(hostname: String?): String? { + return hostnameToId[hostname] + } + + fun getTracker(id: String?): Tracker? { + return trackersById[id] + } +} diff --git a/trackers/src/main/java/foundation/e/privacymodules/trackers/data/WhitelistRepository.kt b/trackers/src/main/java/foundation/e/advancedprivacy/trackers/data/WhitelistRepository.kt similarity index 82% rename from trackers/src/main/java/foundation/e/privacymodules/trackers/data/WhitelistRepository.kt rename to trackers/src/main/java/foundation/e/advancedprivacy/trackers/data/WhitelistRepository.kt index 2763d068..429c5e94 100644 --- a/trackers/src/main/java/foundation/e/privacymodules/trackers/data/WhitelistRepository.kt +++ b/trackers/src/main/java/foundation/e/advancedprivacy/trackers/data/WhitelistRepository.kt @@ -16,15 +16,19 @@ * along with this program. If not, see . */ -package foundation.e.privacymodules.trackers.data +package foundation.e.advancedprivacy.trackers.data import android.content.Context import android.content.SharedPreferences -import foundation.e.privacymodules.permissions.data.ApplicationDescription -import foundation.e.privacymodules.trackers.api.Tracker +import foundation.e.advancedprivacy.data.repositories.AppListsRepository +import foundation.e.advancedprivacy.domain.entities.ApplicationDescription +import foundation.e.advancedprivacy.trackers.domain.entities.Tracker import java.io.File -class WhitelistRepository private constructor(context: Context) { +class WhitelistRepository( + context: Context, + private val appListsRepository: AppListsRepository +) { private var appsWhitelist: Set = HashSet() private var appUidsWhitelist: Set = HashSet() @@ -32,7 +36,6 @@ class WhitelistRepository private constructor(context: Context) { private var trackersWhitelistByUid: Map> = HashMap() private val prefs: SharedPreferences - private var getAppByAPId: ((String) -> ApplicationDescription?)? = null companion object { private const val SHARED_PREFS_FILE = "trackers_whitelist_v2" @@ -41,30 +44,17 @@ class WhitelistRepository private constructor(context: Context) { private const val KEY_APP_TRACKERS_WHITELIST_PREFIX = "app_trackers_whitelist_" private const val SHARED_PREFS_FILE_V1 = "trackers_whitelist.prefs" - - private var instance: WhitelistRepository? = null - fun getInstance(context: Context): WhitelistRepository { - return instance ?: WhitelistRepository(context).apply { instance = this } - } } init { prefs = context.getSharedPreferences(SHARED_PREFS_FILE, Context.MODE_PRIVATE) reloadCache() + migrate(context) } - fun setAppGetters( - context: Context, - getAppByAPId: (String) -> ApplicationDescription?, - getAppByUid: (Int) -> ApplicationDescription? - ) { - this.getAppByAPId = getAppByAPId - migrate(context, getAppByUid) - } - - private fun migrate(context: Context, getAppByUid: (Int) -> ApplicationDescription?) { + private fun migrate(context: Context) { if (context.sharedPreferencesExists(SHARED_PREFS_FILE_V1)) { - migrate1To2(context, getAppByUid) + migrate1To2(context) } } @@ -74,7 +64,7 @@ class WhitelistRepository private constructor(context: Context) { ).exists() } - private fun migrate1To2(context: Context, getAppByUid: (Int) -> ApplicationDescription?) { + private fun migrate1To2(context: Context) { val prefsV1 = context.getSharedPreferences(SHARED_PREFS_FILE_V1, Context.MODE_PRIVATE) val editorV2 = prefs.edit() @@ -83,7 +73,7 @@ class WhitelistRepository private constructor(context: Context) { val apIds = prefsV1.getStringSet(KEY_APPS_WHITELIST, HashSet())?.mapNotNull { try { val uid = it.toInt() - getAppByUid(uid)?.apId + appListsRepository.getApp(uid)?.apId } catch (e: Exception) { null } }?.toSet() ?: HashSet() @@ -93,7 +83,7 @@ class WhitelistRepository private constructor(context: Context) { if (key.startsWith(KEY_APP_TRACKERS_WHITELIST_PREFIX)) { try { val uid = key.substring(KEY_APP_TRACKERS_WHITELIST_PREFIX.length).toInt() - val apId = getAppByUid(uid)?.apId + val apId = appListsRepository.getApp(uid)?.apId apId?.let { val trackers = prefsV1.getStringSet(key, emptySet()) editorV2.putStringSet(buildAppTrackersKey(apId), trackers) @@ -117,13 +107,13 @@ class WhitelistRepository private constructor(context: Context) { private fun reloadAppsWhiteList() { appsWhitelist = prefs.getStringSet(KEY_APPS_WHITELIST, HashSet()) ?: HashSet() appUidsWhitelist = appsWhitelist - .mapNotNull { apId -> getAppByAPId?.invoke(apId)?.uid } + .mapNotNull { apId -> appListsRepository.getApp(apId)?.uid } .toSet() } private fun refreshAppUidTrackersWhiteList() { trackersWhitelistByUid = trackersWhitelistByApp.mapNotNull { (apId, value) -> - getAppByAPId?.invoke(apId)?.uid?.let { uid -> + appListsRepository.getApp(apId)?.uid?.let { uid -> uid to value } }.toMap() @@ -190,9 +180,7 @@ class WhitelistRepository private constructor(context: Context) { } fun getWhiteListedApp(): List { - return getAppByAPId?.let { - appsWhitelist.mapNotNull(it) - } ?: emptyList() + return appsWhitelist.mapNotNull(appListsRepository::getApp) } fun getWhiteListForApp(app: ApplicationDescription): List { diff --git a/trackers/src/main/java/foundation/e/privacymodules/trackers/DNSBlockerRunnable.kt b/trackers/src/main/java/foundation/e/advancedprivacy/trackers/domain/usecases/DNSBlockerRunnable.kt similarity index 92% rename from trackers/src/main/java/foundation/e/privacymodules/trackers/DNSBlockerRunnable.kt rename to trackers/src/main/java/foundation/e/advancedprivacy/trackers/domain/usecases/DNSBlockerRunnable.kt index 44793a4d..0265822a 100644 --- a/trackers/src/main/java/foundation/e/privacymodules/trackers/DNSBlockerRunnable.kt +++ b/trackers/src/main/java/foundation/e/advancedprivacy/trackers/domain/usecases/DNSBlockerRunnable.kt @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -package foundation.e.privacymodules.trackers +package foundation.e.advancedprivacy.trackers.domain.usecases import android.content.Context import android.content.pm.PackageManager @@ -25,8 +25,8 @@ import android.system.ErrnoException import android.system.Os import android.system.OsConstants import android.util.Log -import foundation.e.privacymodules.trackers.data.TrackersRepository -import foundation.e.privacymodules.trackers.data.WhitelistRepository +import foundation.e.advancedprivacy.trackers.data.TrackersRepository +import foundation.e.advancedprivacy.trackers.data.WhitelistRepository import java.io.BufferedReader import java.io.IOException import java.io.InputStreamReader @@ -49,6 +49,7 @@ class DNSBlockerRunnable( } init { + Log.d("RefacKoin", "Starting DNSBlockerRunnable") initEBrowserDoTFix(context) } @@ -56,6 +57,8 @@ class DNSBlockerRunnable( fun stop() { stopped = true closeSocket() + + trackersLogger.stop() } private fun closeSocket() { @@ -79,6 +82,7 @@ class DNSBlockerRunnable( } override fun run() { + val resolverReceiver = try { LocalServerSocket(SOCKET_NAME) } catch (eio: IOException) { @@ -95,6 +99,7 @@ class DNSBlockerRunnable( val reader = BufferedReader(InputStreamReader(socket.inputStream)) val line = reader.readLine() val params = line.split(",").toTypedArray() + Log.d("RefacKoin", "DNSBlockerRunnable: $line") val output = socket.outputStream val writer = PrintWriter(output, true) val domainName = params[0] @@ -108,6 +113,8 @@ class DNSBlockerRunnable( writer.println("block") isBlocked = true } + Log.d("RefacKoin", "DNSBlockerRunnable: asklogaccess") + trackersLogger.logAccess(trackerId, appUid, isBlocked) } if (!isBlocked) { diff --git a/trackers/src/main/java/foundation/e/privacymodules/trackers/data/StatsRepository.kt b/trackers/src/main/java/foundation/e/advancedprivacy/trackers/domain/usecases/StatisticsUseCase.kt similarity index 63% rename from trackers/src/main/java/foundation/e/privacymodules/trackers/data/StatsRepository.kt rename to trackers/src/main/java/foundation/e/advancedprivacy/trackers/domain/usecases/StatisticsUseCase.kt index 8f02adbc..9b8d4c3b 100644 --- a/trackers/src/main/java/foundation/e/privacymodules/trackers/data/StatsRepository.kt +++ b/trackers/src/main/java/foundation/e/advancedprivacy/trackers/domain/usecases/StatisticsUseCase.kt @@ -16,46 +16,34 @@ * along with this program. If not, see . */ -package foundation.e.privacymodules.trackers.data - -import android.content.Context -import foundation.e.privacymodules.permissions.data.ApplicationDescription -import foundation.e.privacymodules.trackers.api.Tracker +package foundation.e.advancedprivacy.trackers.domain.usecases + +import foundation.e.advancedprivacy.data.repositories.AppListsRepository +import foundation.e.advancedprivacy.domain.entities.ApplicationDescription +import foundation.e.advancedprivacy.trackers.data.StatsDatabase +import foundation.e.advancedprivacy.trackers.domain.entities.Tracker +import kotlinx.coroutines.DelicateCoroutinesApi +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.SharedFlow +import kotlinx.coroutines.launch import java.time.temporal.TemporalUnit -class StatsRepository private constructor(context: Context) { - private val database: StatsDatabase - private var newDataCallback: (() -> Unit)? = null - private var getAppByUid: ((Int) -> ApplicationDescription?)? = null - private var getAppByAPId: ((String) -> ApplicationDescription?)? = null - - companion object { - private var instance: StatsRepository? = null - fun getInstance(context: Context): StatsRepository { - return instance ?: StatsRepository(context).apply { instance = this } - } - } - - fun setAppGetters( - getAppByUid: (Int) -> ApplicationDescription?, - getAppByAPId: (String) -> ApplicationDescription? - ) { - this.getAppByUid = getAppByUid - this.getAppByAPId = getAppByAPId - } - - init { - database = StatsDatabase(context) - } - - fun setNewDataCallback(callback: () -> Unit) { - newDataCallback = callback - } +class StatisticsUseCase( + private val database: StatsDatabase, + private val appListsRepository: AppListsRepository +) { + private val _newDataAvailable = MutableSharedFlow() + val newDataAvailable: SharedFlow = _newDataAvailable + @OptIn(DelicateCoroutinesApi::class) fun logAccess(trackerId: String?, appUid: Int, blocked: Boolean) { - getAppByUid?.invoke(appUid)?.let { app -> + appListsRepository.getApp(appUid)?.let { app -> database.logAccess(trackerId, app.apId, blocked) - newDataCallback?.invoke() + // TODO: move the log tracker feature to coroutines. + GlobalScope.launch { + _newDataAvailable.emit(Unit) + } } } @@ -94,12 +82,12 @@ class StatsRepository private constructor(context: Context) { } fun getMostLeakedApp(periodCount: Int, periodUnit: TemporalUnit): ApplicationDescription? { - return getAppByAPId?.invoke(database.getMostLeakedAppId(periodCount, periodUnit)) + return appListsRepository.getApp(database.getMostLeakedAppId(periodCount, periodUnit)) } private fun Map.mapByAppIdToApp(): Map { return entries.mapNotNull { (apId, value) -> - getAppByAPId?.invoke(apId)?.let { it to value } + appListsRepository.getApp(apId)?.let { it to value } }.toMap() } } diff --git a/trackers/src/main/java/foundation/e/privacymodules/trackers/TrackersLogger.kt b/trackers/src/main/java/foundation/e/advancedprivacy/trackers/domain/usecases/TrackersLogger.kt similarity index 78% rename from trackers/src/main/java/foundation/e/privacymodules/trackers/TrackersLogger.kt rename to trackers/src/main/java/foundation/e/advancedprivacy/trackers/domain/usecases/TrackersLogger.kt index f3c4745c..4c5ee7c8 100644 --- a/trackers/src/main/java/foundation/e/privacymodules/trackers/TrackersLogger.kt +++ b/trackers/src/main/java/foundation/e/advancedprivacy/trackers/domain/usecases/TrackersLogger.kt @@ -16,22 +16,17 @@ * along with this program. If not, see . */ -package foundation.e.privacymodules.trackers +package foundation.e.advancedprivacy.trackers.domain.usecases -import android.content.Context -import android.util.Log -import foundation.e.privacymodules.trackers.data.StatsRepository +import timber.log.Timber import java.util.concurrent.LinkedBlockingQueue -class TrackersLogger(context: Context) { - private val statsRepository = StatsRepository.getInstance(context) +class TrackersLogger( + private val statisticsUseCase: StatisticsUseCase +) { private val queue = LinkedBlockingQueue() private var stopped = false - companion object { - private const val TAG = "TrackerModule" - } - init { startWriteLogLoop() } @@ -50,7 +45,7 @@ class TrackersLogger(context: Context) { try { logAccess(queue.take()) } catch (e: InterruptedException) { - Log.e(TAG, "writeLogLoop detectedTrackersQueue.take() interrupted: ", e) + Timber.e("writeLogLoop detectedTrackersQueue.take() interrupted: ", e) } } } @@ -58,7 +53,7 @@ class TrackersLogger(context: Context) { } fun logAccess(detectedTracker: DetectedTracker) { - statsRepository.logAccess( + statisticsUseCase.logAccess( detectedTracker.trackerId, detectedTracker.appUid, detectedTracker.wasBlocked diff --git a/trackers/src/main/java/foundation/e/advancedprivacy/trackers/domain/usecases/UpdateTrackerListUseCase.kt b/trackers/src/main/java/foundation/e/advancedprivacy/trackers/domain/usecases/UpdateTrackerListUseCase.kt new file mode 100644 index 00000000..3593dbb0 --- /dev/null +++ b/trackers/src/main/java/foundation/e/advancedprivacy/trackers/domain/usecases/UpdateTrackerListUseCase.kt @@ -0,0 +1,29 @@ +package foundation.e.advancedprivacy.trackers.domain.usecases + +import foundation.e.advancedprivacy.data.repositories.ETrackersApi +import foundation.e.advancedprivacy.data.repositories.RemoteTrackersListRepository +import foundation.e.advancedprivacy.trackers.data.TrackersRepository +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch +import timber.log.Timber + +class UpdateTrackerListUseCase( + private val remoteTrackersListRepository: RemoteTrackersListRepository, + private val trackersRepository: TrackersRepository, + private val coroutineScope: CoroutineScope, + +) { + fun updateTrackers() = coroutineScope.launch { + update() + } + + suspend fun update() { + val api = ETrackersApi.build() + try { + remoteTrackersListRepository.saveData(trackersRepository.eTrackerFile, api.trackers()) + trackersRepository.initTrackersFile() + } catch (e: Exception) { + Timber.e("While updating trackers", e) + } + } +} diff --git a/trackers/src/main/java/foundation/e/privacymodules/trackers/DNSBlockerService.kt b/trackers/src/main/java/foundation/e/advancedprivacy/trackers/services/DNSBlockerService.kt similarity index 69% rename from trackers/src/main/java/foundation/e/privacymodules/trackers/DNSBlockerService.kt rename to trackers/src/main/java/foundation/e/advancedprivacy/trackers/services/DNSBlockerService.kt index c2ad16b1..63ba3546 100644 --- a/trackers/src/main/java/foundation/e/privacymodules/trackers/DNSBlockerService.kt +++ b/trackers/src/main/java/foundation/e/advancedprivacy/trackers/services/DNSBlockerService.kt @@ -15,20 +15,17 @@ * along with this program. If not, see . */ -package foundation.e.privacymodules.trackers +package foundation.e.advancedprivacy.trackers.services import android.app.Service import android.content.Intent import android.os.IBinder -import android.util.Log -import foundation.e.privacymodules.trackers.data.TrackersRepository -import foundation.e.privacymodules.trackers.data.WhitelistRepository +import foundation.e.advancedprivacy.trackers.domain.usecases.DNSBlockerRunnable +import org.koin.java.KoinJavaComponent.get +import timber.log.Timber class DNSBlockerService : Service() { - private var trackersLogger: TrackersLogger? = null - companion object { - private const val TAG = "DNSBlockerService" private var sDNSBlocker: DNSBlockerRunnable? = null const val ACTION_START = "foundation.e.privacymodules.trackers.intent.action.START" const val EXTRA_ENABLE_NOTIFICATION = @@ -36,7 +33,6 @@ class DNSBlockerService : Service() { } override fun onBind(intent: Intent): IBinder? { - // TODO: Return the communication channel to the service. throw UnsupportedOperationException("Not yet implemented") } @@ -53,18 +49,10 @@ class DNSBlockerService : Service() { private fun start() { try { - val trackersLogger = TrackersLogger(this) - this.trackersLogger = trackersLogger - - sDNSBlocker = DNSBlockerRunnable( - this, - trackersLogger, - TrackersRepository.getInstance(), - WhitelistRepository.getInstance(this) - ) + sDNSBlocker = get(DNSBlockerRunnable::class.java) Thread(sDNSBlocker).start() } catch (e: Exception) { - Log.e(TAG, "Error while starting DNSBlocker service", e) + Timber.e("Error while starting DNSBlocker service", e) stop() } } @@ -72,8 +60,5 @@ class DNSBlockerService : Service() { private fun stop() { sDNSBlocker?.stop() sDNSBlocker = null - - trackersLogger?.stop() - trackersLogger = null } } diff --git a/app/src/main/java/foundation/e/advancedprivacy/UpdateTrackersWorker.kt b/trackers/src/main/java/foundation/e/advancedprivacy/trackers/services/UpdateTrackersWorker.kt similarity index 84% rename from app/src/main/java/foundation/e/advancedprivacy/UpdateTrackersWorker.kt rename to trackers/src/main/java/foundation/e/advancedprivacy/trackers/services/UpdateTrackersWorker.kt index 418f75bb..50aa082d 100644 --- a/app/src/main/java/foundation/e/advancedprivacy/UpdateTrackersWorker.kt +++ b/trackers/src/main/java/foundation/e/advancedprivacy/trackers/services/UpdateTrackersWorker.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package foundation.e.advancedprivacy +package foundation.e.advancedprivacy.trackers.services import android.content.Context import androidx.work.Constraints @@ -25,16 +25,17 @@ import androidx.work.NetworkType import androidx.work.PeriodicWorkRequestBuilder import androidx.work.WorkManager import androidx.work.WorkerParameters +import foundation.e.advancedprivacy.trackers.domain.usecases.UpdateTrackerListUseCase +import org.koin.java.KoinJavaComponent.get import java.util.concurrent.TimeUnit class UpdateTrackersWorker(appContext: Context, workerParams: WorkerParameters) : CoroutineWorker(appContext, workerParams) { override suspend fun doWork(): Result { - val trackersStateUseCase = (applicationContext as AdvancedPrivacyApplication) - .dependencyContainer.trackersStateUseCase + val updateTrackersUsecase: UpdateTrackerListUseCase = get(UpdateTrackerListUseCase::class.java) - trackersStateUseCase.updateTrackers() + updateTrackersUsecase.updateTrackers() return Result.success() } diff --git a/trackers/src/main/java/foundation/e/privacymodules/trackers/api/BlockTrackersPrivacyModule.kt b/trackers/src/main/java/foundation/e/privacymodules/trackers/api/BlockTrackersPrivacyModule.kt deleted file mode 100644 index 7463b224..00000000 --- a/trackers/src/main/java/foundation/e/privacymodules/trackers/api/BlockTrackersPrivacyModule.kt +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (C) 2023 MURENA SAS - * 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.privacymodules.trackers.api - -import android.content.Context -import foundation.e.privacymodules.permissions.data.ApplicationDescription -import foundation.e.privacymodules.trackers.data.TrackersRepository -import foundation.e.privacymodules.trackers.data.WhitelistRepository - -class BlockTrackersPrivacyModule(context: Context) : IBlockTrackersPrivacyModule { - private val mListeners = mutableListOf() - private val trackersRepository = TrackersRepository.getInstance() - private val whitelistRepository = WhitelistRepository.getInstance(context) - - companion object { - private var instance: BlockTrackersPrivacyModule? = null - - fun getInstance(context: Context): BlockTrackersPrivacyModule { - return instance ?: BlockTrackersPrivacyModule(context).apply { instance = this } - } - } - - override fun addListener(listener: IBlockTrackersPrivacyModule.Listener) { - mListeners.add(listener) - } - - override fun clearListeners() { - mListeners.clear() - } - - override fun disableBlocking() { - whitelistRepository.isBlockingEnabled = false - mListeners.forEach { listener -> listener.onBlockingToggle(false) } - } - - override fun enableBlocking() { - whitelistRepository.isBlockingEnabled = true - mListeners.forEach { listener -> listener.onBlockingToggle(true) } - } - - override fun getWhiteList(app: ApplicationDescription): List { - return whitelistRepository.getWhiteListForApp(app).mapNotNull { - trackersRepository.getTracker(it) - } - } - - override fun getWhiteListedApp(): List { - return whitelistRepository.getWhiteListedApp() - } - - override fun isBlockingEnabled(): Boolean { - return whitelistRepository.isBlockingEnabled - } - - override fun isWhiteListEmpty(): Boolean { - return whitelistRepository.areWhiteListEmpty() - } - - override fun isWhitelisted(app: ApplicationDescription): Boolean { - return whitelistRepository.isAppWhiteListed(app) - } - - override fun removeListener(listener: IBlockTrackersPrivacyModule.Listener) { - mListeners.remove(listener) - } - - override fun setWhiteListed( - tracker: Tracker, - app: ApplicationDescription, - isWhiteListed: Boolean - ) { - whitelistRepository.setWhiteListed(tracker, app.apId, isWhiteListed) - } - - override fun setWhiteListed(app: ApplicationDescription, isWhiteListed: Boolean) { - whitelistRepository.setWhiteListed(app.apId, isWhiteListed) - } - - override fun clearWhiteList(app: ApplicationDescription) { - whitelistRepository.clearWhiteList(app.apId) - } -} diff --git a/trackers/src/main/java/foundation/e/privacymodules/trackers/api/IBlockTrackersPrivacyModule.kt b/trackers/src/main/java/foundation/e/privacymodules/trackers/api/IBlockTrackersPrivacyModule.kt deleted file mode 100644 index 3547b8ed..00000000 --- a/trackers/src/main/java/foundation/e/privacymodules/trackers/api/IBlockTrackersPrivacyModule.kt +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (C) 2023 MURENA SAS - * 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.privacymodules.trackers.api - -import foundation.e.privacymodules.permissions.data.ApplicationDescription - -/** - * Manage trackers blocking and whitelisting. - */ -interface IBlockTrackersPrivacyModule { - - /** - * Get the state of the blockin module - * @return true when blocking is enabled, false otherwise. - */ - fun isBlockingEnabled(): Boolean - - /** - * Enable blocking, using the previously configured whitelists - */ - fun enableBlocking() - - /** - * Disable blocking - */ - fun disableBlocking() - - /** - * Set or unset in whitelist the App with the specified uid. - * @param app the ApplicationDescription of the app - * @param isWhiteListed true, the app will appears in whitelist, false, it won't - */ - fun setWhiteListed(app: ApplicationDescription, isWhiteListed: Boolean) - - /** - * Set or unset in whitelist the specifid tracked, for the App specified by its uid. - * @param tracker the tracker - * @param app the ApplicationDescription of the app - * @param isWhiteListed true, the app will appears in whitelist, false, it won't - */ - fun setWhiteListed(tracker: Tracker, app: ApplicationDescription, isWhiteListed: Boolean) - - /** - * Return true if nothing has been added to the whitelist : everything is blocked. - */ - fun isWhiteListEmpty(): Boolean - - /** - * Return the white listed App, by their UID - */ - fun getWhiteListedApp(): List - - /** - * Return true if the App is whitelisted for trackers blocking. - */ - fun isWhitelisted(app: ApplicationDescription): Boolean - - /** - * List the white listed trackers for an App specified by it uid - */ - fun getWhiteList(app: ApplicationDescription): List - - fun clearWhiteList(app: ApplicationDescription) - - /** - * Callback interface to get updates about the state of the Block trackers module. - */ - interface Listener { - - /** - * Called when the trackers blocking is activated or deactivated. - * @param isBlocking true when activated, false otherwise. - */ - fun onBlockingToggle(isBlocking: Boolean) - } - - fun addListener(listener: Listener) - - fun removeListener(listener: Listener) - - fun clearListeners() -} diff --git a/trackers/src/main/java/foundation/e/privacymodules/trackers/api/ITrackTrackersPrivacyModule.kt b/trackers/src/main/java/foundation/e/privacymodules/trackers/api/ITrackTrackersPrivacyModule.kt deleted file mode 100644 index 8aaed4a0..00000000 --- a/trackers/src/main/java/foundation/e/privacymodules/trackers/api/ITrackTrackersPrivacyModule.kt +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2023 MURENA SAS - * 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.privacymodules.trackers.api - -import foundation.e.privacymodules.permissions.data.ApplicationDescription - -/** - * Get reporting about trackers calls. - */ -interface ITrackTrackersPrivacyModule { - - fun start( - trackers: List, - getAppByUid: (Int) -> ApplicationDescription?, - getAppByAPId: (String) -> ApplicationDescription?, - enableNotification: Boolean = true - ) - - /** - * List all the trackers encountered for a specific app. - */ - fun getTrackersForApp(app: ApplicationDescription): List - - /** - * List all the trackers encountere trackers since "ever", for the given [appUids], - * or all apps if [appUids] is null - */ - fun getTrackers(apps: List? = null): List - - /** - * Return the number of encountered trackers since "ever", for the given [appUids], - * or all apps if [appUids] is null - */ - fun getTrackersCount(): Int - - /** - * Return the number of encountere trackers since "ever", for each app uid. - */ - fun getTrackersCountByApp(): Map - - /** - * Return the number of encountered trackers for the last 24 hours - */ - fun getPastDayTrackersCount(): Int - - /** - * Return the number of encountered trackers for the last month - */ - fun getPastMonthTrackersCount(): Int - - /** - * Return the number of encountered trackers for the last year - */ - fun getPastYearTrackersCount(): Int - - /** - * Return number of trackers calls by hours, for the last 24hours. - * @return list of 24 numbers of trackers calls by hours - */ - fun getPastDayTrackersCalls(): List> - - /** - * Return number of trackers calls by day, for the last 30 days. - * @return list of 30 numbers of trackers calls by day - */ - fun getPastMonthTrackersCalls(): List> - - /** - * Return number of trackers calls by month, for the last 12 month. - * @return list of 12 numbers of trackers calls by month - */ - fun getPastYearTrackersCalls(): List> - - fun getPastDayTrackersCallsByApps(): Map> - - fun getPastDayTrackersCallsForApp(app: ApplicationDescription): Pair - - fun getPastDayMostLeakedApp(): ApplicationDescription? - - interface Listener { - - /** - * Called when a new tracker attempt is logged. Consumer may choose to call other methods - * to refresh the data. - */ - fun onNewData() - } - - fun addListener(listener: Listener) - - fun removeListener(listener: Listener) - - fun clearListeners() -} diff --git a/trackers/src/main/java/foundation/e/privacymodules/trackers/api/TrackTrackersPrivacyModule.kt b/trackers/src/main/java/foundation/e/privacymodules/trackers/api/TrackTrackersPrivacyModule.kt deleted file mode 100644 index 5fc5b6b0..00000000 --- a/trackers/src/main/java/foundation/e/privacymodules/trackers/api/TrackTrackersPrivacyModule.kt +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (C) 2023 MURENA SAS - * Copyright (C) 2021 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.privacymodules.trackers.api - -import android.content.Context -import android.content.Intent -import foundation.e.privacymodules.permissions.data.ApplicationDescription -import foundation.e.privacymodules.trackers.DNSBlockerService -import foundation.e.privacymodules.trackers.data.StatsRepository -import foundation.e.privacymodules.trackers.data.TrackersRepository -import foundation.e.privacymodules.trackers.data.WhitelistRepository -import java.time.temporal.ChronoUnit - -class TrackTrackersPrivacyModule(private val context: Context) : ITrackTrackersPrivacyModule { - private val statsRepository = StatsRepository.getInstance(context) - private val listeners: MutableList = mutableListOf() - - companion object { - private var instance: TrackTrackersPrivacyModule? = null - - fun getInstance(context: Context): TrackTrackersPrivacyModule { - return instance ?: TrackTrackersPrivacyModule(context).apply { instance = this } - } - } - - init { - statsRepository.setNewDataCallback { - listeners.forEach { listener -> listener.onNewData() } - } - } - - override fun start( - trackers: List, - getAppByUid: (Int) -> ApplicationDescription?, - getAppByAPId: (String) -> ApplicationDescription?, - enableNotification: Boolean - ) { - TrackersRepository.getInstance().setTrackersList(trackers) - StatsRepository.getInstance(context).setAppGetters(getAppByUid, getAppByAPId) - WhitelistRepository.getInstance(context).setAppGetters(context, getAppByAPId, getAppByUid) - val intent = Intent(context, DNSBlockerService::class.java) - intent.action = DNSBlockerService.ACTION_START - intent.putExtra(DNSBlockerService.EXTRA_ENABLE_NOTIFICATION, enableNotification) - context.startService(intent) - } - - override fun getPastDayTrackersCalls(): List> { - return statsRepository.getTrackersCallsOnPeriod(24, ChronoUnit.HOURS) - } - - override fun getPastMonthTrackersCalls(): List> { - return statsRepository.getTrackersCallsOnPeriod(30, ChronoUnit.DAYS) - } - - override fun getPastYearTrackersCalls(): List> { - return statsRepository.getTrackersCallsOnPeriod(12, ChronoUnit.MONTHS) - } - - override fun getTrackersCount(): Int { - return statsRepository.getContactedTrackersCount() - } - - override fun getTrackersCountByApp(): Map { - return statsRepository.getContactedTrackersCountByApp() - } - - override fun getTrackersForApp(app: ApplicationDescription): List { - return statsRepository.getTrackers(listOf(app)) - } - - override fun getTrackers(apps: List?): List { - return statsRepository.getTrackers(apps) - } - - override fun getPastDayTrackersCount(): Int { - return statsRepository.getActiveTrackersByPeriod(24, ChronoUnit.HOURS) - } - - override fun getPastMonthTrackersCount(): Int { - return statsRepository.getActiveTrackersByPeriod(30, ChronoUnit.DAYS) - } - - override fun getPastYearTrackersCount(): Int { - return statsRepository.getActiveTrackersByPeriod(12, ChronoUnit.MONTHS) - } - - override fun getPastDayMostLeakedApp(): ApplicationDescription? { - return statsRepository.getMostLeakedApp(24, ChronoUnit.HOURS) - } - - override fun getPastDayTrackersCallsByApps(): Map> { - return statsRepository.getCallsByApps(24, ChronoUnit.HOURS) - } - - override fun getPastDayTrackersCallsForApp(app: ApplicationDescription): Pair { - return statsRepository.getCalls(app, 24, ChronoUnit.HOURS) - } - - override fun addListener(listener: ITrackTrackersPrivacyModule.Listener) { - listeners.add(listener) - } - - override fun removeListener(listener: ITrackTrackersPrivacyModule.Listener) { - listeners.remove(listener) - } - - override fun clearListeners() { - listeners.clear() - } -} diff --git a/trackers/src/main/java/foundation/e/privacymodules/trackers/data/TrackersRepository.kt b/trackers/src/main/java/foundation/e/privacymodules/trackers/data/TrackersRepository.kt deleted file mode 100644 index 994bccff..00000000 --- a/trackers/src/main/java/foundation/e/privacymodules/trackers/data/TrackersRepository.kt +++ /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 . - */ - -package foundation.e.privacymodules.trackers.data - -import foundation.e.privacymodules.trackers.api.Tracker - -class TrackersRepository private constructor() { - private var trackersById: Map = HashMap() - private var hostnameToId: Map = HashMap() - - companion object { - private var instance: TrackersRepository? = null - fun getInstance(): TrackersRepository { - return instance ?: TrackersRepository().apply { instance = this } - } - } - - fun setTrackersList(list: List) { - val trackersById: MutableMap = HashMap() - val hostnameToId: MutableMap = HashMap() - list.forEach { tracker -> - trackersById[tracker.id] = tracker - for (hostname in tracker.hostnames) { - hostnameToId[hostname] = tracker.id - } - } - this.trackersById = trackersById - this.hostnameToId = hostnameToId - } - - fun isTracker(hostname: String?): Boolean { - return hostnameToId.containsKey(hostname) - } - - fun getTrackerId(hostname: String?): String? { - return hostnameToId[hostname] - } - - fun getTracker(id: String?): Tracker? { - return trackersById[id] - } -} -- GitLab From cf71dff2e133cde36d4027d38427beb1618d6c53 Mon Sep 17 00:00:00 2001 From: Guillaume Jacquart Date: Wed, 16 Aug 2023 09:39:37 +0200 Subject: [PATCH 3/5] Use Koin for DI. --- app/build.gradle | 8 +- .../AdvancedPrivacyApplication.kt | 53 ++++- .../e/advancedprivacy/DependencyContainer.kt | 210 ------------------ .../e/advancedprivacy/KoinModule.kt | 124 +++++++++++ .../e/advancedprivacy/common/WarningDialog.kt | 5 +- .../features/dashboard/DashboardFragment.kt | 12 +- .../InternetPrivacyFragment.kt | 12 +- .../features/location/FakeLocationFragment.kt | 12 +- .../features/trackers/TrackersFragment.kt | 11 +- .../apptrackers/AppTrackersFragment.kt | 14 +- .../widget/WidgetCommandReceiver.kt | 11 +- core/build.gradle | 52 +++++ .../e/advancedprivacy/core/KoinModule.kt | 23 ++ fakelocation/build.gradle | 8 +- fakelocation/fakelocationdemo/build.gradle | 2 +- .../fakelocationdemo/MainActivity.kt | 10 +- .../fakelocation/KoinModule.kt | 9 + gradle/libs.versions.toml | 5 + ipscrambling/build.gradle | 1 + ipscrambling/orbotservice | 1 - .../advancedprivacy/ipscrambler/KoinModule.kt | 8 + permissionse/build.gradle | 2 +- permissionsstandalone/build.gradle | 2 +- privacymodule-api/.gitignore | 1 - privacymodule-api/build.gradle | 111 --------- privacymodule-api/proguard-rules.pro | 21 -- .../e/privacymodules/DependencyInjector.kt | 31 --- settings.gradle | 4 +- trackers/build.gradle | 9 +- .../e/advancedprivacy/trackers/KoinModule.kt | 57 +++++ .../domain/usecases/DNSBlockerRunnable.kt | 4 - 31 files changed, 375 insertions(+), 458 deletions(-) delete mode 100644 app/src/main/java/foundation/e/advancedprivacy/DependencyContainer.kt create mode 100644 app/src/main/java/foundation/e/advancedprivacy/KoinModule.kt create mode 100644 core/build.gradle create mode 100644 core/src/main/java/foundation/e/advancedprivacy/core/KoinModule.kt create mode 100644 fakelocation/src/main/java/foundation/e/advancedprivacy/fakelocation/KoinModule.kt delete mode 160000 ipscrambling/orbotservice create mode 100644 ipscrambling/src/main/java/foundation/e/advancedprivacy/ipscrambler/KoinModule.kt delete mode 100644 privacymodule-api/.gitignore delete mode 100644 privacymodule-api/build.gradle delete mode 100644 privacymodule-api/proguard-rules.pro delete mode 100644 privacymodule-api/src/main/java/foundation/e/privacymodules/DependencyInjector.kt create mode 100644 trackers/src/main/java/foundation/e/advancedprivacy/trackers/KoinModule.kt diff --git a/app/build.gradle b/app/build.gradle index af05ec08..5ce72f3e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -140,7 +140,7 @@ android { } dependencies { - implementation project(':privacymodule-api') + implementation project(':core') standaloneImplementation project(':permissionsstandalone') eImplementation project(':permissionse') @@ -160,15 +160,13 @@ dependencies { libs.androidx.fragment.ktx, libs.androidx.lifecycle.runtime, libs.androidx.lifecycle.viewmodel, - libs.androidx.work.ktx, + + libs.bundles.koin, libs.google.material, libs.androidx.navigation.fragment, libs.androidx.navigation.ui, - libs.retrofit, - libs.retrofit.scalars, - libs.maplibre, libs.mpandroidcharts, diff --git a/app/src/main/java/foundation/e/advancedprivacy/AdvancedPrivacyApplication.kt b/app/src/main/java/foundation/e/advancedprivacy/AdvancedPrivacyApplication.kt index 9ce0c2b6..a77ced16 100644 --- a/app/src/main/java/foundation/e/advancedprivacy/AdvancedPrivacyApplication.kt +++ b/app/src/main/java/foundation/e/advancedprivacy/AdvancedPrivacyApplication.kt @@ -18,17 +18,60 @@ package foundation.e.advancedprivacy import android.app.Application +import android.content.Intent +import foundation.e.advancedprivacy.common.WarningDialog +import foundation.e.advancedprivacy.domain.usecases.GetQuickPrivacyStateUseCase +import foundation.e.advancedprivacy.domain.usecases.IpScramblingStateUseCase +import foundation.e.advancedprivacy.domain.usecases.ShowFeaturesWarningUseCase +import foundation.e.advancedprivacy.domain.usecases.TrackersStatisticsUseCase +import foundation.e.advancedprivacy.externalinterfaces.permissions.IPermissionsPrivacyModule +import foundation.e.advancedprivacy.trackers.services.DNSBlockerService +import foundation.e.advancedprivacy.trackers.services.UpdateTrackersWorker import foundation.e.lib.telemetry.Telemetry +import kotlinx.coroutines.CoroutineScope +import org.koin.android.ext.koin.androidContext +import org.koin.core.context.startKoin +import org.koin.java.KoinJavaComponent.get class AdvancedPrivacyApplication : Application() { - - // Initialize the dependency container. - val dependencyContainer: DependencyContainer by lazy { DependencyContainer(this) } - override fun onCreate() { super.onCreate() Telemetry.init(BuildConfig.SENTRY_DSN, this, true) - dependencyContainer.initBackgroundSingletons() + startKoin { + androidContext(this@AdvancedPrivacyApplication) + modules(appModule) + } + initBackgroundSingletons() + } + + private fun initBackgroundSingletons() { + UpdateTrackersWorker.periodicUpdate(this) + + WarningDialog.startListening( + get(ShowFeaturesWarningUseCase::class.java), + get(CoroutineScope::class.java), + this + ) + + Widget.startListening( + this, + get(GetQuickPrivacyStateUseCase::class.java), + get(TrackersStatisticsUseCase::class.java), + ) + + Notifications.startListening( + this, + get(GetQuickPrivacyStateUseCase::class.java), + get(IPermissionsPrivacyModule::class.java), + get(CoroutineScope::class.java), + ) + + get(IpScramblingStateUseCase::class.java) + + val intent = Intent(this, DNSBlockerService::class.java) + intent.action = DNSBlockerService.ACTION_START + intent.putExtra(DNSBlockerService.EXTRA_ENABLE_NOTIFICATION, false) + startService(intent) } } diff --git a/app/src/main/java/foundation/e/advancedprivacy/DependencyContainer.kt b/app/src/main/java/foundation/e/advancedprivacy/DependencyContainer.kt deleted file mode 100644 index f6f20389..00000000 --- a/app/src/main/java/foundation/e/advancedprivacy/DependencyContainer.kt +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright (C) 2023 MURENA SAS - * Copyright (C) 2021 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 - -import android.app.Application -import android.content.Context -import android.os.Process -import androidx.lifecycle.DEFAULT_ARGS_KEY -import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider -import androidx.lifecycle.viewmodel.CreationExtras -import foundation.e.advancedprivacy.common.WarningDialog -import foundation.e.advancedprivacy.data.repositories.AppListsRepository -import foundation.e.advancedprivacy.data.repositories.LocalStateRepository -import foundation.e.advancedprivacy.data.repositories.TrackersRepository -import foundation.e.advancedprivacy.domain.usecases.AppListUseCase -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.ShowFeaturesWarningUseCase -import foundation.e.advancedprivacy.domain.usecases.TrackersStateUseCase -import foundation.e.advancedprivacy.domain.usecases.TrackersStatisticsUseCase -import foundation.e.advancedprivacy.dummy.CityDataSource -import foundation.e.advancedprivacy.features.dashboard.DashboardViewModel -import foundation.e.advancedprivacy.features.internetprivacy.InternetPrivacyViewModel -import foundation.e.advancedprivacy.features.location.FakeLocationViewModel -import foundation.e.advancedprivacy.features.trackers.TrackersViewModel -import foundation.e.advancedprivacy.features.trackers.apptrackers.AppTrackersFragmentArgs -import foundation.e.advancedprivacy.features.trackers.apptrackers.AppTrackersViewModel -import foundation.e.privacymodules.fakelocation.FakeLocationModule -import foundation.e.privacymodules.ipscrambler.IIpScramblerModule -import foundation.e.privacymodules.ipscrambler.IpScramblerModule -import foundation.e.privacymodules.permissions.PermissionsPrivacyModule -import foundation.e.privacymodules.permissions.data.ApplicationDescription -import foundation.e.privacymodules.permissions.data.ProfileType -import foundation.e.privacymodules.trackers.api.BlockTrackersPrivacyModule -import foundation.e.privacymodules.trackers.api.TrackTrackersPrivacyModule -import kotlinx.coroutines.DelicateCoroutinesApi -import kotlinx.coroutines.GlobalScope - -/** - * Simple container to hold application wide dependencies. - * - */ -@OptIn(DelicateCoroutinesApi::class) -class DependencyContainer(val app: Application) { - val context: Context by lazy { app.applicationContext } - - // Drivers - private val fakeLocationModule: FakeLocationModule by lazy { FakeLocationModule(app.applicationContext) } - private val permissionsModule by lazy { PermissionsPrivacyModule(app.applicationContext) } - private val ipScramblerModule: IIpScramblerModule by lazy { IpScramblerModule(app.applicationContext) } - - private val appDesc by lazy { - ApplicationDescription( - packageName = context.packageName, - uid = Process.myUid(), - label = context.resources.getString(R.string.app_name), - icon = null, - profileId = -1, - profileType = ProfileType.MAIN - ) - } - - private val blockTrackersPrivacyModule by lazy { BlockTrackersPrivacyModule.getInstance(context) } - private val trackTrackersPrivacyModule by lazy { TrackTrackersPrivacyModule.getInstance(context) } - - // Repositories - private val localStateRepository by lazy { LocalStateRepository(context) } - private val trackersRepository by lazy { TrackersRepository(context) } - private val appListsRepository by lazy { AppListsRepository(permissionsModule, context, GlobalScope) } - - // Usecases - val getQuickPrivacyStateUseCase by lazy { - GetQuickPrivacyStateUseCase(localStateRepository) - } - private val ipScramblingStateUseCase by lazy { - IpScramblingStateUseCase( - ipScramblerModule, permissionsModule, appDesc, localStateRepository, - appListsRepository, GlobalScope - ) - } - private val appListUseCase = AppListUseCase(appListsRepository) - - val trackersStatisticsUseCase by lazy { - TrackersStatisticsUseCase(trackTrackersPrivacyModule, blockTrackersPrivacyModule, appListsRepository, context.resources) - } - - val trackersStateUseCase by lazy { - TrackersStateUseCase(blockTrackersPrivacyModule, trackTrackersPrivacyModule, localStateRepository, trackersRepository, appListsRepository, GlobalScope) - } - - private val fakeLocationStateUseCase by lazy { - FakeLocationStateUseCase( - fakeLocationModule, permissionsModule, localStateRepository, CityDataSource, appDesc, context, GlobalScope - ) - } - - val showFeaturesWarningUseCase by lazy { - ShowFeaturesWarningUseCase(localStateRepository = localStateRepository) - } - - val viewModelsFactory by lazy { - ViewModelsFactory( - getQuickPrivacyStateUseCase = getQuickPrivacyStateUseCase, - trackersStatisticsUseCase = trackersStatisticsUseCase, - trackersStateUseCase = trackersStateUseCase, - fakeLocationStateUseCase = fakeLocationStateUseCase, - ipScramblerModule = ipScramblerModule, - ipScramblingStateUseCase = ipScramblingStateUseCase, - appListUseCase = appListUseCase - ) - } - - // Background - fun initBackgroundSingletons() { - trackersStateUseCase - ipScramblingStateUseCase - fakeLocationStateUseCase - - UpdateTrackersWorker.periodicUpdate(context) - - WarningDialog.startListening( - showFeaturesWarningUseCase, - GlobalScope, - context - ) - - Widget.startListening( - context, - getQuickPrivacyStateUseCase, - trackersStatisticsUseCase, - ) - - Notifications.startListening( - context, - getQuickPrivacyStateUseCase, - permissionsModule, - GlobalScope - ) - } -} - -@Suppress("LongParameterList") -class ViewModelsFactory( - private val getQuickPrivacyStateUseCase: GetQuickPrivacyStateUseCase, - private val trackersStatisticsUseCase: TrackersStatisticsUseCase, - private val trackersStateUseCase: TrackersStateUseCase, - private val fakeLocationStateUseCase: FakeLocationStateUseCase, - private val ipScramblerModule: IIpScramblerModule, - private val ipScramblingStateUseCase: IpScramblingStateUseCase, - private val appListUseCase: AppListUseCase -) : ViewModelProvider.Factory { - - @Suppress("UNCHECKED_CAST") - override fun create(modelClass: Class, extras: CreationExtras): T { - return when (modelClass) { - AppTrackersViewModel::class.java -> { - val app = extras[DEFAULT_ARGS_KEY]?.let { - appListUseCase.getApp(AppTrackersFragmentArgs.fromBundle(it).appUid) - } ?: appListUseCase.dummySystemApp - - AppTrackersViewModel( - app = app, - trackersStateUseCase = trackersStateUseCase, - trackersStatisticsUseCase = trackersStatisticsUseCase, - getQuickPrivacyStateUseCase = getQuickPrivacyStateUseCase - ) - } - - TrackersViewModel::class.java -> - TrackersViewModel( - trackersStatisticsUseCase = trackersStatisticsUseCase - ) - FakeLocationViewModel::class.java -> - FakeLocationViewModel( - fakeLocationStateUseCase = fakeLocationStateUseCase - ) - InternetPrivacyViewModel::class.java -> - InternetPrivacyViewModel( - ipScramblerModule = ipScramblerModule, - getQuickPrivacyStateUseCase = getQuickPrivacyStateUseCase, - ipScramblingStateUseCase = ipScramblingStateUseCase, - appListUseCase = appListUseCase - ) - DashboardViewModel::class.java -> - DashboardViewModel( - getPrivacyStateUseCase = getQuickPrivacyStateUseCase, - trackersStatisticsUseCase = trackersStatisticsUseCase - ) - else -> throw IllegalArgumentException("Unknown class $modelClass") - } as T - } -} diff --git a/app/src/main/java/foundation/e/advancedprivacy/KoinModule.kt b/app/src/main/java/foundation/e/advancedprivacy/KoinModule.kt new file mode 100644 index 00000000..534aa6bd --- /dev/null +++ b/app/src/main/java/foundation/e/advancedprivacy/KoinModule.kt @@ -0,0 +1,124 @@ +package foundation.e.advancedprivacy + +import android.content.res.Resources +import android.os.Process +import foundation.e.advancedprivacy.core.coreModule +import foundation.e.advancedprivacy.data.repositories.LocalStateRepository +import foundation.e.advancedprivacy.domain.entities.ApplicationDescription +import foundation.e.advancedprivacy.domain.entities.ProfileType +import foundation.e.advancedprivacy.domain.usecases.AppListUseCase +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.ShowFeaturesWarningUseCase +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 +import foundation.e.advancedprivacy.features.trackers.TrackersViewModel +import foundation.e.advancedprivacy.features.trackers.apptrackers.AppTrackersViewModel +import foundation.e.advancedprivacy.ipscrambler.ipScramblerModule +import foundation.e.advancedprivacy.permissions.externalinterfaces.PermissionsPrivacyModule +import foundation.e.advancedprivacy.trackers.trackersModule +import org.koin.android.ext.koin.androidContext +import org.koin.androidx.viewmodel.dsl.viewModel +import org.koin.androidx.viewmodel.dsl.viewModelOf +import org.koin.core.module.dsl.singleOf +import org.koin.core.qualifier.named +import org.koin.dsl.module + +val appModule = module { + includes(coreModule, trackersModule, fakelocationModule, ipScramblerModule) + + factory { androidContext().resources } + single { + LocalStateRepository(context = androidContext()) + } + + single(named("AdvancedPrivacy")) { + ApplicationDescription( + packageName = androidContext().packageName, + uid = Process.myUid(), + label = androidContext().resources.getString(R.string.app_name), + icon = null, + profileId = -1, + profileType = ProfileType.MAIN + ) + } + + single(named("DummySystemApp")) { + ApplicationDescription( + packageName = "foundation.e.dummysystemapp", + uid = -1, + label = androidContext().getString(R.string.dummy_system_app_label), + icon = androidContext().getDrawable(R.drawable.ic_e_app_logo), + profileId = -1, + profileType = ProfileType.MAIN + ) + } + + single(named("DummyCompatibilityApp")) { + ApplicationDescription( + packageName = "foundation.e.dummyappscompatibilityapp", + uid = -2, + label = androidContext().getString(R.string.dummy_apps_compatibility_app_label), + icon = androidContext().getDrawable(R.drawable.ic_apps_compatibility_components), + profileId = -1, + profileType = ProfileType.MAIN + ) + } + + single { CityDataSource } + + singleOf(::AppListUseCase) + single { + FakeLocationStateUseCase( + fakeLocationModule = get(), + permissionsModule = get(), + localStateRepository = get(), + citiesRepository = get(), + appDesc = get(named("AdvancedPrivacy")), + appContext = androidContext(), + coroutineScope = get() + ) + } + + singleOf(::GetQuickPrivacyStateUseCase) + single { + IpScramblingStateUseCase( + ipScramblerModule = get(), + permissionsPrivacyModule = get(), + appDesc = get(named("AdvancedPrivacy")), + localStateRepository = get(), + appListsRepository = get(), + coroutineScope = get() + ) + } + singleOf(::ShowFeaturesWarningUseCase) + singleOf(::TrackersStateUseCase) + singleOf(::TrackersStatisticsUseCase) + + single { + PermissionsPrivacyModule(context = androidContext()) + } + + viewModel { parameters -> + val appListUseCase: AppListUseCase = get() + val app = appListUseCase.getApp(parameters.get()) + + AppTrackersViewModel( + app = app, + trackersStateUseCase = get(), + trackersStatisticsUseCase = get(), + getQuickPrivacyStateUseCase = get() + ) + } + viewModelOf(::TrackersViewModel) + viewModelOf(::FakeLocationViewModel) + viewModelOf(::InternetPrivacyViewModel) + viewModelOf(::DashboardViewModel) +} diff --git a/app/src/main/java/foundation/e/advancedprivacy/common/WarningDialog.kt b/app/src/main/java/foundation/e/advancedprivacy/common/WarningDialog.kt index 3f3f66cd..1a836924 100644 --- a/app/src/main/java/foundation/e/advancedprivacy/common/WarningDialog.kt +++ b/app/src/main/java/foundation/e/advancedprivacy/common/WarningDialog.kt @@ -27,7 +27,6 @@ import android.util.Log import android.view.View import android.widget.CheckBox import androidx.appcompat.app.AlertDialog -import foundation.e.advancedprivacy.AdvancedPrivacyApplication import foundation.e.advancedprivacy.R import foundation.e.advancedprivacy.domain.entities.MainFeatures import foundation.e.advancedprivacy.domain.entities.MainFeatures.FAKE_LOCATION @@ -38,6 +37,7 @@ import foundation.e.advancedprivacy.main.MainActivity import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.map +import org.koin.java.KoinJavaComponent.get class WarningDialog : Activity() { companion object { @@ -112,8 +112,7 @@ class WarningDialog : Activity() { } ) { _, _ -> if (checkbox.isChecked()) { - (application as AdvancedPrivacyApplication) - .dependencyContainer.showFeaturesWarningUseCase + get(ShowFeaturesWarningUseCase::class.java) .doNotShowAgain(feature) } finish() 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 6ca97922..5eb0bb6e 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 @@ -25,14 +25,11 @@ import android.view.View import android.widget.Toast import androidx.core.content.ContextCompat.getColor import androidx.core.view.isVisible -import androidx.fragment.app.viewModels import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs -import foundation.e.advancedprivacy.AdvancedPrivacyApplication -import foundation.e.advancedprivacy.DependencyContainer import foundation.e.advancedprivacy.R import foundation.e.advancedprivacy.common.GraphHolder import foundation.e.advancedprivacy.common.NavToolbarFragment @@ -44,15 +41,10 @@ import foundation.e.advancedprivacy.domain.entities.TrackerMode import foundation.e.advancedprivacy.features.dashboard.DashboardViewModel.Action import foundation.e.advancedprivacy.features.dashboard.DashboardViewModel.SingleEvent import kotlinx.coroutines.launch +import org.koin.androidx.viewmodel.ext.android.viewModel class DashboardFragment : NavToolbarFragment(R.layout.fragment_dashboard) { - private val dependencyContainer: DependencyContainer by lazy { - (this.requireActivity().application as AdvancedPrivacyApplication).dependencyContainer - } - - private val viewModel: DashboardViewModel by viewModels { - dependencyContainer.viewModelsFactory - } + private val viewModel: DashboardViewModel by viewModel() private var graphHolder: GraphHolder? = null 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 35fc1d40..1180af30 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 @@ -23,13 +23,10 @@ import android.view.View import android.widget.AdapterView import android.widget.ArrayAdapter import android.widget.Toast -import androidx.fragment.app.viewModels import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle import androidx.recyclerview.widget.LinearLayoutManager -import foundation.e.advancedprivacy.AdvancedPrivacyApplication -import foundation.e.advancedprivacy.DependencyContainer import foundation.e.advancedprivacy.R import foundation.e.advancedprivacy.common.NavToolbarFragment import foundation.e.advancedprivacy.common.ToggleAppsAdapter @@ -37,17 +34,12 @@ import foundation.e.advancedprivacy.common.setToolTipForAsterisk import foundation.e.advancedprivacy.databinding.FragmentInternetActivityPolicyBinding import foundation.e.advancedprivacy.domain.entities.InternetPrivacyMode import kotlinx.coroutines.launch +import org.koin.androidx.viewmodel.ext.android.viewModel import java.util.Locale class InternetPrivacyFragment : NavToolbarFragment(R.layout.fragment_internet_activity_policy) { - private val dependencyContainer: DependencyContainer by lazy { - (this.requireActivity().application as AdvancedPrivacyApplication).dependencyContainer - } - - private val viewModel: InternetPrivacyViewModel by viewModels { - dependencyContainer.viewModelsFactory - } + private val viewModel: InternetPrivacyViewModel by viewModel() private var _binding: FragmentInternetActivityPolicyBinding? = null private val binding get() = _binding!! 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 7d189304..1c629c2c 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 @@ -31,7 +31,6 @@ import androidx.activity.result.contract.ActivityResultContracts import androidx.annotation.NonNull import androidx.core.view.isVisible import androidx.core.widget.addTextChangedListener -import androidx.fragment.app.viewModels import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle @@ -50,8 +49,6 @@ import com.mapbox.mapboxsdk.location.modes.CameraMode import com.mapbox.mapboxsdk.location.modes.RenderMode import com.mapbox.mapboxsdk.maps.MapboxMap import com.mapbox.mapboxsdk.maps.Style -import foundation.e.advancedprivacy.AdvancedPrivacyApplication -import foundation.e.advancedprivacy.DependencyContainer import foundation.e.advancedprivacy.R import foundation.e.advancedprivacy.common.NavToolbarFragment import foundation.e.advancedprivacy.databinding.FragmentFakeLocationBinding @@ -60,19 +57,14 @@ import foundation.e.advancedprivacy.features.location.FakeLocationViewModel.Acti import kotlinx.coroutines.Job import kotlinx.coroutines.delay import kotlinx.coroutines.launch +import org.koin.androidx.viewmodel.ext.android.viewModel import timber.log.Timber class FakeLocationFragment : NavToolbarFragment(R.layout.fragment_fake_location) { private var isFirstLaunch: Boolean = true - private val dependencyContainer: DependencyContainer by lazy { - (this.requireActivity().application as AdvancedPrivacyApplication).dependencyContainer - } - - private val viewModel: FakeLocationViewModel by viewModels { - dependencyContainer.viewModelsFactory - } + private val viewModel: FakeLocationViewModel by viewModel() private var _binding: FragmentFakeLocationBinding? = null private val binding get() = _binding!! diff --git a/app/src/main/java/foundation/e/advancedprivacy/features/trackers/TrackersFragment.kt b/app/src/main/java/foundation/e/advancedprivacy/features/trackers/TrackersFragment.kt index f4861145..132fa3b4 100644 --- a/app/src/main/java/foundation/e/advancedprivacy/features/trackers/TrackersFragment.kt +++ b/app/src/main/java/foundation/e/advancedprivacy/features/trackers/TrackersFragment.kt @@ -31,14 +31,11 @@ import android.view.View import android.widget.Toast import androidx.core.content.ContextCompat import androidx.core.view.isVisible -import androidx.fragment.app.viewModels import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.LinearLayoutManager -import foundation.e.advancedprivacy.AdvancedPrivacyApplication -import foundation.e.advancedprivacy.DependencyContainer import foundation.e.advancedprivacy.R import foundation.e.advancedprivacy.common.AppsAdapter import foundation.e.advancedprivacy.common.GraphHolder @@ -48,14 +45,10 @@ import foundation.e.advancedprivacy.databinding.FragmentTrackersBinding import foundation.e.advancedprivacy.databinding.TrackersItemGraphBinding import foundation.e.advancedprivacy.domain.entities.TrackersPeriodicStatistics import kotlinx.coroutines.launch +import org.koin.androidx.viewmodel.ext.android.viewModel class TrackersFragment : NavToolbarFragment(R.layout.fragment_trackers) { - - private val dependencyContainer: DependencyContainer by lazy { - (this.requireActivity().application as AdvancedPrivacyApplication).dependencyContainer - } - - private val viewModel: TrackersViewModel by viewModels { dependencyContainer.viewModelsFactory } + private val viewModel: TrackersViewModel by viewModel() private var _binding: FragmentTrackersBinding? = null private val binding get() = _binding!! diff --git a/app/src/main/java/foundation/e/advancedprivacy/features/trackers/apptrackers/AppTrackersFragment.kt b/app/src/main/java/foundation/e/advancedprivacy/features/trackers/apptrackers/AppTrackersFragment.kt index 457a02a0..7fb9ca6d 100644 --- a/app/src/main/java/foundation/e/advancedprivacy/features/trackers/apptrackers/AppTrackersFragment.kt +++ b/app/src/main/java/foundation/e/advancedprivacy/features/trackers/apptrackers/AppTrackersFragment.kt @@ -24,27 +24,23 @@ import android.os.Bundle import android.view.View import android.widget.Toast import androidx.core.view.isVisible -import androidx.fragment.app.viewModels import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle +import androidx.navigation.fragment.navArgs import androidx.recyclerview.widget.LinearLayoutManager import com.google.android.material.snackbar.Snackbar -import foundation.e.advancedprivacy.AdvancedPrivacyApplication -import foundation.e.advancedprivacy.DependencyContainer import foundation.e.advancedprivacy.R import foundation.e.advancedprivacy.common.NavToolbarFragment import foundation.e.advancedprivacy.databinding.ApptrackersFragmentBinding import kotlinx.coroutines.launch +import org.koin.androidx.viewmodel.ext.android.viewModel +import org.koin.core.parameter.parametersOf class AppTrackersFragment : NavToolbarFragment(R.layout.apptrackers_fragment) { - private val dependencyContainer: DependencyContainer by lazy { - (this.requireActivity().application as AdvancedPrivacyApplication).dependencyContainer - } - private val viewModel: AppTrackersViewModel by viewModels { - dependencyContainer.viewModelsFactory - } + private val args: AppTrackersFragmentArgs by navArgs() + private val viewModel: AppTrackersViewModel by viewModel { parametersOf(args.appUid) } private var _binding: ApptrackersFragmentBinding? = null private val binding get() = _binding!! diff --git a/app/src/main/java/foundation/e/advancedprivacy/widget/WidgetCommandReceiver.kt b/app/src/main/java/foundation/e/advancedprivacy/widget/WidgetCommandReceiver.kt index 90211252..917cbda3 100644 --- a/app/src/main/java/foundation/e/advancedprivacy/widget/WidgetCommandReceiver.kt +++ b/app/src/main/java/foundation/e/advancedprivacy/widget/WidgetCommandReceiver.kt @@ -20,11 +20,12 @@ package foundation.e.advancedprivacy.widget import android.content.BroadcastReceiver import android.content.Context import android.content.Intent -import foundation.e.advancedprivacy.AdvancedPrivacyApplication +import foundation.e.advancedprivacy.domain.usecases.GetQuickPrivacyStateUseCase +import org.koin.java.KoinJavaComponent.get class WidgetCommandReceiver : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { - val getQuickPrivacyStateUseCase = (context?.applicationContext as? AdvancedPrivacyApplication)?.dependencyContainer?.getQuickPrivacyStateUseCase + val getQuickPrivacyStateUseCase = get(GetQuickPrivacyStateUseCase::class.java) val featureEnabled = intent?.extras?.let { bundle -> if (bundle.containsKey(PARAM_FEATURE_ENABLED)) @@ -32,9 +33,9 @@ class WidgetCommandReceiver : BroadcastReceiver() { else null } when (intent?.action) { - ACTION_TOGGLE_TRACKERS -> getQuickPrivacyStateUseCase?.toggleTrackers(featureEnabled) - ACTION_TOGGLE_LOCATION -> getQuickPrivacyStateUseCase?.toggleLocation(featureEnabled) - ACTION_TOGGLE_IPSCRAMBLING -> getQuickPrivacyStateUseCase?.toggleIpScrambling(featureEnabled) + ACTION_TOGGLE_TRACKERS -> getQuickPrivacyStateUseCase.toggleTrackers(featureEnabled) + ACTION_TOGGLE_LOCATION -> getQuickPrivacyStateUseCase.toggleLocation(featureEnabled) + ACTION_TOGGLE_IPSCRAMBLING -> getQuickPrivacyStateUseCase.toggleIpScrambling(featureEnabled) else -> {} } } diff --git a/core/build.gradle b/core/build.gradle new file mode 100644 index 00000000..0e53f22b --- /dev/null +++ b/core/build.gradle @@ -0,0 +1,52 @@ +/* + * 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 . + */ + +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' + +group 'foundation.e' + +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_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } +} + +dependencies { + implementation( + libs.androidx.core.ktx, + libs.bundles.koin, + libs.kotlinx.coroutines + ) +} diff --git a/core/src/main/java/foundation/e/advancedprivacy/core/KoinModule.kt b/core/src/main/java/foundation/e/advancedprivacy/core/KoinModule.kt new file mode 100644 index 00000000..141da866 --- /dev/null +++ b/core/src/main/java/foundation/e/advancedprivacy/core/KoinModule.kt @@ -0,0 +1,23 @@ +package foundation.e.advancedprivacy.core + +import foundation.e.advancedprivacy.data.repositories.AppListsRepository +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.DelicateCoroutinesApi +import kotlinx.coroutines.GlobalScope +import org.koin.android.ext.koin.androidContext +import org.koin.core.qualifier.named +import org.koin.dsl.module + +@OptIn(DelicateCoroutinesApi::class) +val coreModule = module { + single { GlobalScope } + single { + AppListsRepository( + permissionsModule = get(), + dummySystemApp = get(named("DummySystemApp")), + dummyCompatibilityApp = get(named("DummyCompatibilityApp")), + context = androidContext(), + coroutineScope = get() + ) + } +} diff --git a/fakelocation/build.gradle b/fakelocation/build.gradle index 91f80315..64fc6336 100644 --- a/fakelocation/build.gradle +++ b/fakelocation/build.gradle @@ -46,7 +46,11 @@ android { } dependencies { - implementation (libs.bundles.kotlin.android.coroutines) - implementation project(':privacymodule-api') + implementation( + libs.bundles.koin, + libs.bundles.kotlin.android.coroutines + ) + implementation project(':core') + } diff --git a/fakelocation/fakelocationdemo/build.gradle b/fakelocation/fakelocationdemo/build.gradle index 0145eca3..6cb9af3a 100644 --- a/fakelocation/fakelocationdemo/build.gradle +++ b/fakelocation/fakelocationdemo/build.gradle @@ -54,7 +54,7 @@ android { } dependencies { - implementation project(':privacymodule-api') + implementation project(':core') implementation project(':fakelocation') implementation project(':permissionsstandalone') diff --git a/fakelocation/fakelocationdemo/src/main/java/foundation/e/privacymodules/fakelocationdemo/MainActivity.kt b/fakelocation/fakelocationdemo/src/main/java/foundation/e/privacymodules/fakelocationdemo/MainActivity.kt index b7c9ceda..f2e10a44 100644 --- a/fakelocation/fakelocationdemo/src/main/java/foundation/e/privacymodules/fakelocationdemo/MainActivity.kt +++ b/fakelocation/fakelocationdemo/src/main/java/foundation/e/privacymodules/fakelocationdemo/MainActivity.kt @@ -33,12 +33,12 @@ import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity import androidx.core.content.ContextCompat import androidx.databinding.DataBindingUtil -import foundation.e.privacymodules.fakelocation.FakeLocationModule +import foundation.e.advancedprivacy.domain.entities.AppOpModes +import foundation.e.advancedprivacy.domain.entities.ApplicationDescription +import foundation.e.advancedprivacy.domain.entities.ProfileType +import foundation.e.advancedprivacy.fakelocation.domain.usecases.FakeLocationModule +import foundation.e.advancedprivacy.permissions.externalinterfaces.PermissionsPrivacyModule import foundation.e.privacymodules.fakelocationdemo.databinding.ActivityMainBinding -import foundation.e.privacymodules.permissions.PermissionsPrivacyModule -import foundation.e.privacymodules.permissions.data.AppOpModes -import foundation.e.privacymodules.permissions.data.ApplicationDescription -import foundation.e.privacymodules.permissions.data.ProfileType class MainActivity : AppCompatActivity() { companion object { diff --git a/fakelocation/src/main/java/foundation/e/advancedprivacy/fakelocation/KoinModule.kt b/fakelocation/src/main/java/foundation/e/advancedprivacy/fakelocation/KoinModule.kt new file mode 100644 index 00000000..b833181b --- /dev/null +++ b/fakelocation/src/main/java/foundation/e/advancedprivacy/fakelocation/KoinModule.kt @@ -0,0 +1,9 @@ +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/gradle/libs.versions.toml b/gradle/libs.versions.toml index e85838df..b9925d41 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,6 @@ [versions] +koin = "3.2.0" kotlinx-coroutines = "1.6.1" kotlin = "1.6.10" androidx-navigation = "2.5.3" @@ -31,7 +32,10 @@ e-elib = { group = "foundation.e", name = "elib", version = "0.0.1-alpha11" } e-orbotservice = { group = "foundation.e", name = "orbotservice", version.ref = "orbotservice" } e-telemetry = { group = "foundation.e.lib", name = "telemetry", version = "0.0.8-alpha" } google-material = { group = "com.google.android.material", name = "material", version = "1.6.1" } +google-gson = { group = "com.google.code.gson", name = "gson", version = "2.10.1" } junit = { group = "junit", name = "junit", version = "4.13.1" } +koin-core = { group = "io.insert-koin", name = "koin-core", version.ref = "koin" } +koin-android = { group = "io.insert-koin", name = "koin-android", version.ref = "koin" } kotlinx-coroutines-android = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-android", version.ref = "kotlinx-coroutines" } kotlinx-coroutines = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" } leakcanary = { group = "com.squareup.leakcanary", name = "leakcanary-android", version = "2.9.1" } @@ -44,6 +48,7 @@ timber = { group = "com.jakewharton.timber", name = "timber", version = "5.0.1" [bundles] +koin = ["koin-core", "koin-android"] kotlin-android-coroutines = ["androidx-core-ktx", "kotlinx-coroutines"] [plugins] diff --git a/ipscrambling/build.gradle b/ipscrambling/build.gradle index 0e293df2..39efce74 100644 --- a/ipscrambling/build.gradle +++ b/ipscrambling/build.gradle @@ -47,6 +47,7 @@ android { dependencies { implementation( + libs.bundles.koin, libs.bundles.kotlin.android.coroutines, libs.androidx.localbroadcast, ) diff --git a/ipscrambling/orbotservice b/ipscrambling/orbotservice deleted file mode 160000 index 1930a046..00000000 --- a/ipscrambling/orbotservice +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 1930a046eff2dd37d23ffd83f0064f60334468a5 diff --git a/ipscrambling/src/main/java/foundation/e/advancedprivacy/ipscrambler/KoinModule.kt b/ipscrambling/src/main/java/foundation/e/advancedprivacy/ipscrambler/KoinModule.kt new file mode 100644 index 00000000..4f80ef48 --- /dev/null +++ b/ipscrambling/src/main/java/foundation/e/advancedprivacy/ipscrambler/KoinModule.kt @@ -0,0 +1,8 @@ +package foundation.e.advancedprivacy.ipscrambler + +import org.koin.core.module.dsl.singleOf +import org.koin.dsl.module + +val ipScramblerModule = module { + singleOf(::IpScramblerModule) +} diff --git a/permissionse/build.gradle b/permissionse/build.gradle index 90e06225..7b6ff48d 100644 --- a/permissionse/build.gradle +++ b/permissionse/build.gradle @@ -27,6 +27,6 @@ dependencies { compileOnly project(':permissionse:libs:hidden-apis-stub') implementation(libs.bundles.kotlin.android.coroutines) + implementation project(':core') - implementation project(':privacymodule-api') } diff --git a/permissionsstandalone/build.gradle b/permissionsstandalone/build.gradle index cf3563e4..e330d314 100644 --- a/permissionsstandalone/build.gradle +++ b/permissionsstandalone/build.gradle @@ -47,7 +47,7 @@ android { dependencies { implementation(libs.bundles.kotlin.android.coroutines) - implementation project(':privacymodule-api') + implementation project(':core') testImplementation libs.junit diff --git a/privacymodule-api/.gitignore b/privacymodule-api/.gitignore deleted file mode 100644 index 42afabfd..00000000 --- a/privacymodule-api/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build \ No newline at end of file diff --git a/privacymodule-api/build.gradle b/privacymodule-api/build.gradle deleted file mode 100644 index 259672bf..00000000 --- a/privacymodule-api/build.gradle +++ /dev/null @@ -1,111 +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 . - */ - -apply plugin: 'com.android.library' -apply plugin: 'kotlin-android' -apply plugin: 'maven-publish' - -group 'foundation.e' - -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_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } -} - -dependencies { - implementation( - libs.androidx.core.ktx, - libs.kotlinx.coroutines - ) -} - -//url "https://gitlab.e.foundation/api/v4/groups/e/privacy-central/-/packages/maven" - -publishing { - publications { - maven(MavenPublication) { - groupId 'foundation.e' - //You can either define these here or get them from project conf elsewhere - artifactId 'privacymodule-api' - version buildConfig.version.name - artifact "$buildDir/outputs/aar/privacymodule-api-release.aar" - //aar artifact you want to publish - - //generate pom nodes for dependencies - pom.withXml { - def dependenciesNode = asNode().appendNode('dependencies') - configurations.implementation.allDependencies.each { dependency -> - if (dependency.name != 'unspecified') { - def dependencyNode = dependenciesNode.appendNode('dependency') - dependencyNode.appendNode('groupId', dependency.group) - dependencyNode.appendNode('artifactId', dependency.name) - dependencyNode.appendNode('version', dependency.version) - } - } - } - repositories { - def ciJobToken = System.getenv("CI_JOB_TOKEN") - def ciApiV4Url = System.getenv("CI_API_V4_URL") - if (ciJobToken != null) { - maven { - url "${ciApiV4Url}/projects/900/packages/maven" - credentials(HttpHeaderCredentials) { - name = 'Job-Token' - value = ciJobToken - } - authentication { - header(HttpHeaderAuthentication) - } - } - } else { - maven { -// url "https://gitlab.e.foundation/api/v4/projects/900/packages/maven" - // Use privacymodule-e repository (id = 781) for now, - // because repository not activated on Advanced Privacy (id = 900) - url "https://gitlab.e.foundation/api/v4/projects/781/packages/maven" - credentials(HttpHeaderCredentials) { - name = "Private-Token" - value = gitLabPrivateToken - // the variable resides in ~/.gradle/gradle.properties - } - authentication { - header(HttpHeaderAuthentication) - } - } - } - } - } - } -} diff --git a/privacymodule-api/proguard-rules.pro b/privacymodule-api/proguard-rules.pro deleted file mode 100644 index 481bb434..00000000 --- a/privacymodule-api/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/privacymodule-api/src/main/java/foundation/e/privacymodules/DependencyInjector.kt b/privacymodule-api/src/main/java/foundation/e/privacymodules/DependencyInjector.kt deleted file mode 100644 index 9bf8abac..00000000 --- a/privacymodule-api/src/main/java/foundation/e/privacymodules/DependencyInjector.kt +++ /dev/null @@ -1,31 +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.privacymodules - -import foundation.e.privacymodules.trackers.IDNSBlocker - -object DependencyInjector { - fun initialize( - dnsBlocker: IDNSBlocker - ) { - this.dnsBlocker = dnsBlocker - } - - lateinit var dnsBlocker: IDNSBlocker - private set -} diff --git a/settings.gradle b/settings.gradle index c9b8f062..1b54f0d5 100644 --- a/settings.gradle +++ b/settings.gradle @@ -12,13 +12,13 @@ include ':app' rootProject.name = "AdvancedPrivacy" include ':fakelocation' include ':fakelocation:fakelocationdemo' -include ':privacymodule-api' +include ':core' include ':permissionsstandalone' include ':trackers' include ':permissionse' include ':permissionse:libs:hidden-apis-stub' include ':ipscrambling' -include ':ipscrambling:orbotservice' +//include ':ipscrambling:orbotservice' dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) diff --git a/trackers/build.gradle b/trackers/build.gradle index bb9489a5..737db5a9 100644 --- a/trackers/build.gradle +++ b/trackers/build.gradle @@ -1,4 +1,5 @@ /* + Copyright (C) 2023 MURENA SAS Copyright (C) 2022 ECORP This program is free software; you can redistribute it and/or @@ -42,9 +43,15 @@ android { } dependencies { - implementation project(':privacymodule-api') + implementation project(':core') implementation( + libs.androidx.work.ktx, + libs.bundles.koin, libs.bundles.kotlin.android.coroutines, + libs.google.gson, + libs.retrofit, + libs.retrofit.scalars, + libs.timber ) } diff --git a/trackers/src/main/java/foundation/e/advancedprivacy/trackers/KoinModule.kt b/trackers/src/main/java/foundation/e/advancedprivacy/trackers/KoinModule.kt new file mode 100644 index 00000000..d7e9a2b7 --- /dev/null +++ b/trackers/src/main/java/foundation/e/advancedprivacy/trackers/KoinModule.kt @@ -0,0 +1,57 @@ +package foundation.e.advancedprivacy.trackers + +import foundation.e.advancedprivacy.data.repositories.RemoteTrackersListRepository +import foundation.e.advancedprivacy.trackers.data.StatsDatabase +import foundation.e.advancedprivacy.trackers.data.TrackersRepository +import foundation.e.advancedprivacy.trackers.data.WhitelistRepository +import foundation.e.advancedprivacy.trackers.domain.usecases.DNSBlockerRunnable +import foundation.e.advancedprivacy.trackers.domain.usecases.StatisticsUseCase +import foundation.e.advancedprivacy.trackers.domain.usecases.TrackersLogger +import foundation.e.advancedprivacy.trackers.domain.usecases.UpdateTrackerListUseCase +import org.koin.android.ext.koin.androidContext +import org.koin.core.module.dsl.factoryOf +import org.koin.core.module.dsl.singleOf +import org.koin.dsl.module + +val trackersModule = module { + + factoryOf(::RemoteTrackersListRepository) + factoryOf(::UpdateTrackerListUseCase) + + singleOf(::TrackersRepository) + single { + StatsDatabase( + context = androidContext(), + trackersRepository = get() + ) + } + + single { + StatisticsUseCase( + database = get(), + appListsRepository = get() + ) + } + + single { + WhitelistRepository( + context = androidContext(), + appListsRepository = get() + ) + } + + factory { + DNSBlockerRunnable( + context = androidContext(), + trackersLogger = get(), + trackersRepository = get(), + whitelistRepository = get() + ) + } + + factory { + TrackersLogger( + statisticsUseCase = get() + ) + } +} diff --git a/trackers/src/main/java/foundation/e/advancedprivacy/trackers/domain/usecases/DNSBlockerRunnable.kt b/trackers/src/main/java/foundation/e/advancedprivacy/trackers/domain/usecases/DNSBlockerRunnable.kt index 0265822a..914324d4 100644 --- a/trackers/src/main/java/foundation/e/advancedprivacy/trackers/domain/usecases/DNSBlockerRunnable.kt +++ b/trackers/src/main/java/foundation/e/advancedprivacy/trackers/domain/usecases/DNSBlockerRunnable.kt @@ -49,7 +49,6 @@ class DNSBlockerRunnable( } init { - Log.d("RefacKoin", "Starting DNSBlockerRunnable") initEBrowserDoTFix(context) } @@ -99,7 +98,6 @@ class DNSBlockerRunnable( val reader = BufferedReader(InputStreamReader(socket.inputStream)) val line = reader.readLine() val params = line.split(",").toTypedArray() - Log.d("RefacKoin", "DNSBlockerRunnable: $line") val output = socket.outputStream val writer = PrintWriter(output, true) val domainName = params[0] @@ -113,8 +111,6 @@ class DNSBlockerRunnable( writer.println("block") isBlocked = true } - Log.d("RefacKoin", "DNSBlockerRunnable: asklogaccess") - trackersLogger.logAccess(trackerId, appUid, isBlocked) } if (!isBlocked) { -- GitLab From 6cbe0266cb83f9f53e9c4d0bbd3c4e31616d51b6 Mon Sep 17 00:00:00 2001 From: Guillaume Jacquart Date: Mon, 21 Aug 2023 15:16:25 +0200 Subject: [PATCH 4/5] Fix toggle fakelocation just after launch. --- .../e/advancedprivacy/AdvancedPrivacyApplication.kt | 4 ++++ ipscrambling/src/main/AndroidManifest.xml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/foundation/e/advancedprivacy/AdvancedPrivacyApplication.kt b/app/src/main/java/foundation/e/advancedprivacy/AdvancedPrivacyApplication.kt index a77ced16..0af2a0e9 100644 --- a/app/src/main/java/foundation/e/advancedprivacy/AdvancedPrivacyApplication.kt +++ b/app/src/main/java/foundation/e/advancedprivacy/AdvancedPrivacyApplication.kt @@ -20,9 +20,11 @@ package foundation.e.advancedprivacy import android.app.Application import android.content.Intent import foundation.e.advancedprivacy.common.WarningDialog +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.ShowFeaturesWarningUseCase +import foundation.e.advancedprivacy.domain.usecases.TrackersStateUseCase import foundation.e.advancedprivacy.domain.usecases.TrackersStatisticsUseCase import foundation.e.advancedprivacy.externalinterfaces.permissions.IPermissionsPrivacyModule import foundation.e.advancedprivacy.trackers.services.DNSBlockerService @@ -68,6 +70,8 @@ class AdvancedPrivacyApplication : Application() { ) get(IpScramblingStateUseCase::class.java) + get(FakeLocationStateUseCase::class.java) + get(TrackersStateUseCase::class.java) val intent = Intent(this, DNSBlockerService::class.java) intent.action = DNSBlockerService.ACTION_START diff --git a/ipscrambling/src/main/AndroidManifest.xml b/ipscrambling/src/main/AndroidManifest.xml index e9481477..d6496f0e 100644 --- a/ipscrambling/src/main/AndroidManifest.xml +++ b/ipscrambling/src/main/AndroidManifest.xml @@ -1,5 +1,5 @@ -- GitLab From d56b8b16acd09ca22a15aa2b5fc7c9acce985ee6 Mon Sep 17 00:00:00 2001 From: Guillaume Jacquart Date: Fri, 8 Sep 2023 09:26:45 +0200 Subject: [PATCH 5/5] Refac tracker controle thread to coroutine. Fix ANR --- .../core/utils/CoroutinesUtils.kt | 45 +++++++++++++ .../e/advancedprivacy/trackers/KoinModule.kt | 25 +++++-- .../{DNSBlockerRunnable.kt => DNSBlocker.kt} | 65 +++++++++---------- .../domain/usecases/StatisticsUseCase.kt | 11 +--- .../domain/usecases/TrackersLogger.kt | 32 ++++----- .../trackers/services/DNSBlockerService.kt | 26 ++++---- 6 files changed, 128 insertions(+), 76 deletions(-) create mode 100644 core/src/main/java/foundation/e/advancedprivacy/core/utils/CoroutinesUtils.kt rename trackers/src/main/java/foundation/e/advancedprivacy/trackers/domain/usecases/{DNSBlockerRunnable.kt => DNSBlocker.kt} (74%) diff --git a/core/src/main/java/foundation/e/advancedprivacy/core/utils/CoroutinesUtils.kt b/core/src/main/java/foundation/e/advancedprivacy/core/utils/CoroutinesUtils.kt new file mode 100644 index 00000000..5344c6a9 --- /dev/null +++ b/core/src/main/java/foundation/e/advancedprivacy/core/utils/CoroutinesUtils.kt @@ -0,0 +1,45 @@ +/* + * 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.core.utils + +import kotlinx.coroutines.CancellationException +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract + +@OptIn(ExperimentalContracts::class) +inline fun runSuspendCatching(block: () -> T): Result { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + + return runCatching(block).onFailure { + if (it is CancellationException) { + throw it + } + } +} + +inline fun Result.recoverSuspendCatching( + transform: (exception: Throwable) -> R +): Result { + return when (val exception = exceptionOrNull()) { + null -> this + else -> runSuspendCatching { transform(exception) } + } +} 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 d7e9a2b7..0cfb69cf 100644 --- a/trackers/src/main/java/foundation/e/advancedprivacy/trackers/KoinModule.kt +++ b/trackers/src/main/java/foundation/e/advancedprivacy/trackers/KoinModule.kt @@ -1,10 +1,27 @@ +/* + * 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.trackers import foundation.e.advancedprivacy.data.repositories.RemoteTrackersListRepository import foundation.e.advancedprivacy.trackers.data.StatsDatabase import foundation.e.advancedprivacy.trackers.data.TrackersRepository import foundation.e.advancedprivacy.trackers.data.WhitelistRepository -import foundation.e.advancedprivacy.trackers.domain.usecases.DNSBlockerRunnable +import foundation.e.advancedprivacy.trackers.domain.usecases.DNSBlocker import foundation.e.advancedprivacy.trackers.domain.usecases.StatisticsUseCase import foundation.e.advancedprivacy.trackers.domain.usecases.TrackersLogger import foundation.e.advancedprivacy.trackers.domain.usecases.UpdateTrackerListUseCase @@ -41,7 +58,7 @@ val trackersModule = module { } factory { - DNSBlockerRunnable( + DNSBlocker( context = androidContext(), trackersLogger = get(), trackersRepository = get(), @@ -50,8 +67,6 @@ val trackersModule = module { } factory { - TrackersLogger( - statisticsUseCase = get() - ) + TrackersLogger(statisticsUseCase = get()) } } diff --git a/trackers/src/main/java/foundation/e/advancedprivacy/trackers/domain/usecases/DNSBlockerRunnable.kt b/trackers/src/main/java/foundation/e/advancedprivacy/trackers/domain/usecases/DNSBlocker.kt similarity index 74% rename from trackers/src/main/java/foundation/e/advancedprivacy/trackers/domain/usecases/DNSBlockerRunnable.kt rename to trackers/src/main/java/foundation/e/advancedprivacy/trackers/domain/usecases/DNSBlocker.kt index 914324d4..fb089103 100644 --- a/trackers/src/main/java/foundation/e/advancedprivacy/trackers/domain/usecases/DNSBlockerRunnable.kt +++ b/trackers/src/main/java/foundation/e/advancedprivacy/trackers/domain/usecases/DNSBlocker.kt @@ -24,42 +24,38 @@ import android.net.LocalServerSocket import android.system.ErrnoException import android.system.Os import android.system.OsConstants -import android.util.Log +import foundation.e.advancedprivacy.core.utils.runSuspendCatching import foundation.e.advancedprivacy.trackers.data.TrackersRepository import foundation.e.advancedprivacy.trackers.data.WhitelistRepository +import kotlinx.coroutines.CancellationException +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.isActive +import kotlinx.coroutines.launch +import timber.log.Timber import java.io.BufferedReader -import java.io.IOException import java.io.InputStreamReader import java.io.PrintWriter -class DNSBlockerRunnable( +class DNSBlocker( context: Context, - private val trackersLogger: TrackersLogger, + val trackersLogger: TrackersLogger, private val trackersRepository: TrackersRepository, private val whitelistRepository: WhitelistRepository -) : Runnable { - var resolverReceiver: LocalServerSocket? = null - var stopped = false +) { + private var resolverReceiver: LocalServerSocket? = null private var eBrowserAppUid = -1 companion object { private const val SOCKET_NAME = "foundation.e.advancedprivacy" private const val E_BROWSER_DOT_SERVER = "chrome.cloudflare-dns.com" - private const val TAG = "DNSBlockerRunnable" } init { initEBrowserDoTFix(context) } - @Synchronized - fun stop() { - stopped = true - closeSocket() - - trackersLogger.stop() - } - private fun closeSocket() { // Known bug and workaround that LocalServerSocket::close is not working well // https://issuetracker.google.com/issues/36945762 @@ -70,30 +66,29 @@ class DNSBlockerRunnable( resolverReceiver = null } catch (e: ErrnoException) { if (e.errno != OsConstants.EBADF) { - Log.w(TAG, "Socket already closed") + Timber.w("Socket already closed") } else { - Log.e(TAG, "Exception: cannot close DNS port on stop $SOCKET_NAME !", e) + Timber.e(e, "Exception: cannot close DNS port on stop $SOCKET_NAME !") } } catch (e: Exception) { - Log.e(TAG, "Exception: cannot close DNS port on stop $SOCKET_NAME !", e) + Timber.e(e, "Exception: cannot close DNS port on stop $SOCKET_NAME !") } } } - override fun run() { - - val resolverReceiver = try { + fun listenJob(scope: CoroutineScope): Job = scope.launch(Dispatchers.IO) { + val resolverReceiver = runSuspendCatching { LocalServerSocket(SOCKET_NAME) - } catch (eio: IOException) { - Log.e(TAG, "Exception:Cannot open DNS port $SOCKET_NAME !", eio) - return + }.getOrElse { + Timber.e(it, "Exception: cannot open DNS port on $SOCKET_NAME") + return@launch } - this.resolverReceiver = resolverReceiver - Log.d(TAG, "DNSFilterProxy running on port $SOCKET_NAME !") + this@DNSBlocker.resolverReceiver = resolverReceiver + Timber.d("DNSFilterProxy running on port $SOCKET_NAME") - while (!stopped) { - try { + while (isActive) { + runSuspendCatching { val socket = resolverReceiver.accept() val reader = BufferedReader(InputStreamReader(socket.inputStream)) val line = reader.readLine() @@ -117,9 +112,13 @@ class DNSBlockerRunnable( writer.println("pass") } socket.close() - // Printing bufferedreader data - } catch (e: IOException) { - Log.w(TAG, "Exception while listening DNS resolver", e) + }.onFailure { + if (it is CancellationException) { + closeSocket() + throw it + } else { + Timber.w(it, "Exception while listening DNS resolver") + } } } } @@ -129,7 +128,7 @@ class DNSBlockerRunnable( eBrowserAppUid = context.packageManager.getApplicationInfo("foundation.e.browser", 0).uid } catch (e: PackageManager.NameNotFoundException) { - Log.i(TAG, "no E Browser package found.") + Timber.i(e, "no E Browser package found.") } } diff --git a/trackers/src/main/java/foundation/e/advancedprivacy/trackers/domain/usecases/StatisticsUseCase.kt b/trackers/src/main/java/foundation/e/advancedprivacy/trackers/domain/usecases/StatisticsUseCase.kt index 9b8d4c3b..55efeb99 100644 --- a/trackers/src/main/java/foundation/e/advancedprivacy/trackers/domain/usecases/StatisticsUseCase.kt +++ b/trackers/src/main/java/foundation/e/advancedprivacy/trackers/domain/usecases/StatisticsUseCase.kt @@ -22,11 +22,8 @@ import foundation.e.advancedprivacy.data.repositories.AppListsRepository import foundation.e.advancedprivacy.domain.entities.ApplicationDescription import foundation.e.advancedprivacy.trackers.data.StatsDatabase import foundation.e.advancedprivacy.trackers.domain.entities.Tracker -import kotlinx.coroutines.DelicateCoroutinesApi -import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.SharedFlow -import kotlinx.coroutines.launch import java.time.temporal.TemporalUnit class StatisticsUseCase( @@ -36,14 +33,10 @@ class StatisticsUseCase( private val _newDataAvailable = MutableSharedFlow() val newDataAvailable: SharedFlow = _newDataAvailable - @OptIn(DelicateCoroutinesApi::class) - fun logAccess(trackerId: String?, appUid: Int, blocked: Boolean) { + suspend fun logAccess(trackerId: String?, appUid: Int, blocked: Boolean) { appListsRepository.getApp(appUid)?.let { app -> database.logAccess(trackerId, app.apId, blocked) - // TODO: move the log tracker feature to coroutines. - GlobalScope.launch { - _newDataAvailable.emit(Unit) - } + _newDataAvailable.emit(Unit) } } diff --git a/trackers/src/main/java/foundation/e/advancedprivacy/trackers/domain/usecases/TrackersLogger.kt b/trackers/src/main/java/foundation/e/advancedprivacy/trackers/domain/usecases/TrackersLogger.kt index 4c5ee7c8..411b4ab6 100644 --- a/trackers/src/main/java/foundation/e/advancedprivacy/trackers/domain/usecases/TrackersLogger.kt +++ b/trackers/src/main/java/foundation/e/advancedprivacy/trackers/domain/usecases/TrackersLogger.kt @@ -18,41 +18,37 @@ package foundation.e.advancedprivacy.trackers.domain.usecases +import foundation.e.advancedprivacy.core.utils.runSuspendCatching +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.isActive +import kotlinx.coroutines.launch import timber.log.Timber import java.util.concurrent.LinkedBlockingQueue class TrackersLogger( - private val statisticsUseCase: StatisticsUseCase + private val statisticsUseCase: StatisticsUseCase, ) { private val queue = LinkedBlockingQueue() - private var stopped = false - - init { - startWriteLogLoop() - } - - fun stop() { - stopped = true - } fun logAccess(trackerId: String?, appUid: Int, wasBlocked: Boolean) { queue.offer(DetectedTracker(trackerId, appUid, wasBlocked)) } - private fun startWriteLogLoop() { - val writeLogRunner = Runnable { - while (!stopped) { - try { + fun writeLogJob(scope: CoroutineScope): Job { + return scope.launch(Dispatchers.IO) { + while (isActive) { + runSuspendCatching { logAccess(queue.take()) - } catch (e: InterruptedException) { - Timber.e("writeLogLoop detectedTrackersQueue.take() interrupted: ", e) + }.onFailure { + Timber.e(it, "writeLogLoop detectedTrackersQueue.take() interrupted: ") } } } - Thread(writeLogRunner).start() } - fun logAccess(detectedTracker: DetectedTracker) { + private suspend fun logAccess(detectedTracker: DetectedTracker) { statisticsUseCase.logAccess( detectedTracker.trackerId, detectedTracker.appUid, diff --git a/trackers/src/main/java/foundation/e/advancedprivacy/trackers/services/DNSBlockerService.kt b/trackers/src/main/java/foundation/e/advancedprivacy/trackers/services/DNSBlockerService.kt index 63ba3546..25539e18 100644 --- a/trackers/src/main/java/foundation/e/advancedprivacy/trackers/services/DNSBlockerService.kt +++ b/trackers/src/main/java/foundation/e/advancedprivacy/trackers/services/DNSBlockerService.kt @@ -1,4 +1,5 @@ /* + * Copyright (C) 2023 MURENA SAS * Copyright (C) 2021 E FOUNDATION * * This program is free software: you can redistribute it and/or modify @@ -20,18 +21,22 @@ package foundation.e.advancedprivacy.trackers.services import android.app.Service import android.content.Intent import android.os.IBinder -import foundation.e.advancedprivacy.trackers.domain.usecases.DNSBlockerRunnable +import foundation.e.advancedprivacy.trackers.domain.usecases.DNSBlocker +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.cancel import org.koin.java.KoinJavaComponent.get -import timber.log.Timber class DNSBlockerService : Service() { companion object { - private var sDNSBlocker: DNSBlockerRunnable? = null const val ACTION_START = "foundation.e.privacymodules.trackers.intent.action.START" const val EXTRA_ENABLE_NOTIFICATION = "foundation.e.privacymodules.trackers.intent.extra.ENABLED_NOTIFICATION" } + private var coroutineScope = CoroutineScope(Dispatchers.IO) + private var dnsBlocker: DNSBlocker? = null + override fun onBind(intent: Intent): IBinder? { throw UnsupportedOperationException("Not yet implemented") } @@ -48,17 +53,16 @@ class DNSBlockerService : Service() { } private fun start() { - try { - sDNSBlocker = get(DNSBlockerRunnable::class.java) - Thread(sDNSBlocker).start() - } catch (e: Exception) { - Timber.e("Error while starting DNSBlocker service", e) - stop() + coroutineScope = CoroutineScope(Dispatchers.IO) + get(DNSBlocker::class.java).apply { + this@DNSBlockerService.dnsBlocker = this + trackersLogger.writeLogJob(coroutineScope) + listenJob(coroutineScope) } } private fun stop() { - sDNSBlocker?.stop() - sDNSBlocker = null + kotlin.runCatching { coroutineScope.cancel() } + dnsBlocker = null } } -- GitLab