aboutsummaryrefslogtreecommitdiffstats
path: root/app/src/main/java/foundation/e/advancedprivacy/domain
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/java/foundation/e/advancedprivacy/domain')
-rw-r--r--app/src/main/java/foundation/e/advancedprivacy/domain/usecases/AppTrackersUseCase.kt83
-rw-r--r--app/src/main/java/foundation/e/advancedprivacy/domain/usecases/TrackerDetailsUseCase.kt55
-rw-r--r--app/src/main/java/foundation/e/advancedprivacy/domain/usecases/TrackersAndAppsListsUseCase.kt78
-rw-r--r--app/src/main/java/foundation/e/advancedprivacy/domain/usecases/TrackersStateUseCase.kt20
-rw-r--r--app/src/main/java/foundation/e/advancedprivacy/domain/usecases/TrackersStatisticsUseCase.kt86
5 files changed, 224 insertions, 98 deletions
diff --git a/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/AppTrackersUseCase.kt b/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/AppTrackersUseCase.kt
new file mode 100644
index 0000000..92550ab
--- /dev/null
+++ b/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/AppTrackersUseCase.kt
@@ -0,0 +1,83 @@
+/*
+ * 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 <https://www.gnu.org/licenses/>.
+ */
+package foundation.e.advancedprivacy.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.data.TrackersRepository
+import foundation.e.advancedprivacy.trackers.data.WhitelistRepository
+import foundation.e.advancedprivacy.trackers.domain.entities.Tracker
+import foundation.e.advancedprivacy.trackers.domain.usecases.FilterHostnameUseCase
+
+class AppTrackersUseCase(
+ private val whitelistRepository: WhitelistRepository,
+ private val trackersStateUseCase: TrackersStateUseCase,
+ private val appListsRepository: AppListsRepository,
+ private val statsDatabase: StatsDatabase,
+ private val trackersRepository: TrackersRepository,
+ private val filterHostnameUseCase: FilterHostnameUseCase,
+) {
+ suspend fun toggleAppWhitelist(app: ApplicationDescription, isBlocked: Boolean) {
+ appListsRepository.applyForHiddenApps(app) {
+ whitelistRepository.setWhiteListed(it.apId, !isBlocked)
+ val trackerIds = statsDatabase.getTrackerIds(listOf(app.apId))
+ whitelistRepository.setWhitelistedTrackersForApp(it.apId, trackerIds, !isBlocked)
+ }
+ trackersStateUseCase.updateAllTrackersBlockedState()
+ }
+
+ suspend fun clearWhitelist(app: ApplicationDescription) {
+ appListsRepository.applyForHiddenApps(
+ app
+ ) {
+ whitelistRepository.clearWhiteList(it.apId)
+ }
+ trackersStateUseCase.updateAllTrackersBlockedState()
+ }
+
+ suspend fun getCalls(app: ApplicationDescription): Pair<Int, Int> {
+ return appListsRepository.mapReduceForHiddenApps(
+ app = app,
+ map = {
+ statsDatabase.getCallsForApp(app.apId)
+ },
+ reduce = { zip ->
+ zip.unzip().let { (blocked, leaked) ->
+ blocked.sum() to leaked.sum()
+ }
+ }
+ )
+ }
+
+ suspend fun getTrackersWithBlockedList(app: ApplicationDescription): List<Pair<Tracker, Boolean>> {
+ val realApIds = appListsRepository.getRealApps(app).map { it.apId }
+ val trackers = statsDatabase.getTrackerIds(realApIds)
+ .mapNotNull { trackersRepository.getTracker(it) }
+
+ return enrichWithBlockedState(app, trackers)
+ }
+
+ suspend fun enrichWithBlockedState(app: ApplicationDescription, trackers: List<Tracker>): List<Pair<Tracker, Boolean>> {
+ val realAppUids = appListsRepository.getRealApps(app).map { it.uid }
+ return trackers.map { tracker ->
+ tracker to !realAppUids.any { uid ->
+ filterHostnameUseCase.isWhitelisted(uid, tracker.id)
+ }
+ }.sortedBy { it.first.label.lowercase() }
+ }
+}
diff --git a/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/TrackerDetailsUseCase.kt b/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/TrackerDetailsUseCase.kt
new file mode 100644
index 0000000..27f3e78
--- /dev/null
+++ b/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/TrackerDetailsUseCase.kt
@@ -0,0 +1,55 @@
+/*
+ * 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 <https://www.gnu.org/licenses/>.
+ */
+package foundation.e.advancedprivacy.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.data.WhitelistRepository
+import foundation.e.advancedprivacy.trackers.domain.entities.Tracker
+import foundation.e.advancedprivacy.trackers.domain.usecases.FilterHostnameUseCase
+
+class TrackerDetailsUseCase(
+ private val whitelistRepository: WhitelistRepository,
+ private val trackersStateUseCase: TrackersStateUseCase,
+ private val appListsRepository: AppListsRepository,
+ private val statsDatabase: StatsDatabase,
+ private val filterHostnameUseCase: FilterHostnameUseCase,
+) {
+ suspend fun toggleTrackerWhitelist(tracker: Tracker, isBlocked: Boolean) {
+ whitelistRepository.setWhiteListed(tracker, !isBlocked)
+ whitelistRepository.setWhitelistedAppsForTracker(statsDatabase.getApIds(tracker.id), tracker.id, !isBlocked)
+ trackersStateUseCase.updateAllTrackersBlockedState()
+ }
+
+ suspend fun getAppsWithBlockedState(tracker: Tracker): List<Pair<ApplicationDescription, Boolean>> {
+ return enrichWithBlockedState(
+ statsDatabase.getApIds(tracker.id).mapNotNull {
+ appListsRepository.getDisplayableApp(it)
+ }.sortedBy { it.label?.toString() },
+ tracker
+ )
+ }
+
+ suspend fun enrichWithBlockedState(apps: List<ApplicationDescription>, tracker: Tracker): List<Pair<ApplicationDescription, Boolean>> {
+ return apps.map { it to !filterHostnameUseCase.isWhitelisted(it.uid, tracker.id) }
+ }
+
+ suspend fun getCalls(tracker: Tracker): Pair<Int, Int> {
+ return statsDatabase.getCallsForTracker(tracker.id)
+ }
+}
diff --git a/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/TrackersAndAppsListsUseCase.kt b/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/TrackersAndAppsListsUseCase.kt
new file mode 100644
index 0000000..8292a6d
--- /dev/null
+++ b/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/TrackersAndAppsListsUseCase.kt
@@ -0,0 +1,78 @@
+/*
+ * 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 <https://www.gnu.org/licenses/>.
+ */
+package foundation.e.advancedprivacy.domain.usecases
+
+import foundation.e.advancedprivacy.data.repositories.AppListsRepository
+import foundation.e.advancedprivacy.domain.entities.ApplicationDescription
+import foundation.e.advancedprivacy.features.trackers.AppWithTrackersCount
+import foundation.e.advancedprivacy.features.trackers.TrackerWithAppsCount
+import foundation.e.advancedprivacy.trackers.data.StatsDatabase
+import foundation.e.advancedprivacy.trackers.data.TrackersRepository
+import foundation.e.advancedprivacy.trackers.domain.entities.Tracker
+import kotlinx.coroutines.flow.first
+
+class TrackersAndAppsListsUseCase(
+ private val statsDatabase: StatsDatabase,
+ private val trackersRepository: TrackersRepository,
+ private val appListsRepository: AppListsRepository,
+) {
+
+ suspend fun getAppsAndTrackersCounts(): Pair<List<AppWithTrackersCount>, List<TrackerWithAppsCount>> {
+ val trackersAndAppsIds = statsDatabase.getDistinctTrackerAndApp()
+ val trackersAndApps = mapIdsToEntities(trackersAndAppsIds)
+ val (countByApp, countByTracker) = foldToCountByEntityMaps(trackersAndApps)
+
+ val appList = buildAppList(countByApp)
+ val trackerList = buildTrackerList(countByTracker)
+ return appList to trackerList
+ }
+
+ private fun buildTrackerList(countByTracker: Map<Tracker, Int>): List<TrackerWithAppsCount> {
+ return countByTracker.map { (tracker, count) ->
+ TrackerWithAppsCount(tracker = tracker, appsCount = count)
+ }.sortedByDescending { it.appsCount }
+ }
+
+ private suspend fun buildAppList(countByApp: Map<ApplicationDescription, Int>): List<AppWithTrackersCount> {
+ return appListsRepository.apps().first().map { app: ApplicationDescription ->
+ AppWithTrackersCount(app = app, trackersCount = countByApp[app] ?: 0)
+ }.sortedByDescending { it.trackersCount }
+ }
+
+ private suspend fun mapIdsToEntities(trackersAndAppsIds: List<Pair<String, String>>): List<Pair<Tracker, ApplicationDescription>> {
+ return trackersAndAppsIds.mapNotNull { (trackerId, apId) ->
+ trackersRepository.getTracker(trackerId)?.let { tracker ->
+ appListsRepository.getDisplayableApp(apId)?.let { app ->
+ tracker to app
+ }
+ }
+ // appListsRepository.getDisplayableApp() may transform many apId to one
+ // ApplicationDescription, so the lists is not distinct anymore.
+ }.distinct()
+ }
+
+ private fun foldToCountByEntityMaps(trackersAndApps: List<Pair<Tracker, ApplicationDescription>>):
+ Pair<Map<ApplicationDescription, Int>, Map<Tracker, Int>> {
+ return trackersAndApps.fold(
+ mutableMapOf<ApplicationDescription, Int>() to mutableMapOf<Tracker, Int>()
+ ) { (countByApp, countByTracker), (tracker, app) ->
+ countByApp[app] = countByApp.getOrDefault(app, 0) + 1
+ countByTracker[tracker] = countByTracker.getOrDefault(tracker, 0) + 1
+ countByApp to countByTracker
+ }
+ }
+}
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 2c47d70..dddc6a2 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
@@ -41,7 +41,7 @@ class TrackersStateUseCase(
}
}
- private fun updateAllTrackersBlockedState() {
+ fun updateAllTrackersBlockedState() {
localStateRepository.areAllTrackersBlocked.value = whitelistRepository.isBlockingEnabled &&
whitelistRepository.areWhiteListEmpty()
}
@@ -50,28 +50,16 @@ class TrackersStateUseCase(
return isWhitelisted(app, appListsRepository, whitelistRepository)
}
- fun toggleAppWhitelist(app: ApplicationDescription, isWhitelisted: Boolean) {
- appListsRepository.applyForHiddenApps(app) {
- whitelistRepository.setWhiteListed(it.apId, isWhitelisted)
- }
- updateAllTrackersBlockedState()
+ fun isWhitelisted(tracker: Tracker): Boolean {
+ return whitelistRepository.isWhiteListed(tracker)
}
- fun blockTracker(app: ApplicationDescription, tracker: Tracker, isBlocked: Boolean) {
+ suspend fun blockTracker(app: ApplicationDescription, tracker: Tracker, isBlocked: Boolean) {
appListsRepository.applyForHiddenApps(app) {
whitelistRepository.setWhiteListed(tracker, it.apId, !isBlocked)
}
updateAllTrackersBlockedState()
}
-
- fun clearWhitelist(app: ApplicationDescription) {
- appListsRepository.applyForHiddenApps(
- app
- ) {
- whitelistRepository.clearWhiteList(it.apId)
- }
- updateAllTrackersBlockedState()
- }
}
fun isWhitelisted(
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 3d6ade0..8f290b8 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
@@ -1,5 +1,6 @@
/*
- * Copyright (C) 2021 E FOUNDATION, 2022 - 2023 MURENA SAS
+ * Copyright (C) 2022 - 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
@@ -21,7 +22,6 @@ import android.content.res.Resources
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.advancedprivacy.trackers.data.StatsDatabase
@@ -167,27 +167,7 @@ class TrackersStatisticsUseCase(
)
}
- fun getTrackersWithWhiteList(app: ApplicationDescription): List<Pair<Tracker, Boolean>> {
- return appListsRepository.mapReduceForHiddenApps(
- app = app,
- map = { appDesc: ApplicationDescription ->
- (
- statisticsUseCase.getTrackers(listOf(appDesc)) to
- getWhiteList(appDesc)
- )
- },
- reduce = { lists ->
- lists.unzip().let { (trackerLists, whiteListedIdLists) ->
- val whiteListedIds = whiteListedIdLists.flatten().map { it.id }.toSet()
-
- trackerLists.flatten().distinctBy { it.id }.sortedBy { it.label.lowercase() }
- .map { tracker -> tracker to (tracker.id in whiteListedIds) }
- }
- }
- )
- }
-
- fun isWhiteListEmpty(app: ApplicationDescription): Boolean {
+ suspend fun isWhiteListEmpty(app: ApplicationDescription): Boolean {
return appListsRepository.mapReduceForHiddenApps(
app = app,
map = { appDesc: ApplicationDescription ->
@@ -197,7 +177,7 @@ class TrackersStatisticsUseCase(
)
}
- fun getCalls(app: ApplicationDescription): Pair<Int, Int> {
+ suspend fun getCalls(app: ApplicationDescription): Pair<Int, Int> {
return appListsRepository.mapReduceForHiddenApps(
app = app,
map = {
@@ -211,67 +191,9 @@ class TrackersStatisticsUseCase(
)
}
- fun getAppsWithCounts(): Flow<List<AppWithCounts>> {
- val trackersCounts = statisticsUseCase.getContactedTrackersCountByApp()
- val hiddenAppsTrackersWithWhiteList =
- getTrackersWithWhiteList(appListsRepository.dummySystemApp)
- val acAppsTrackersWithWhiteList =
- getTrackersWithWhiteList(appListsRepository.dummyCompatibilityApp)
-
- return appListsRepository.apps()
- .map { apps ->
- val callsByApp = statisticsUseCase.getCallsByApps(24, ChronoUnit.HOURS)
- apps.map { app ->
- val calls = appListsRepository.mapReduceForHiddenApps(
- app = app,
- map = { callsByApp.getOrDefault(app, 0 to 0) },
- reduce = {
- it.unzip().let { (blocked, leaked) ->
- blocked.sum() to leaked.sum()
- }
- }
- )
-
- AppWithCounts(
- app = app,
- isWhitelisted = !whitelistRepository.isBlockingEnabled ||
- isWhitelisted(app, appListsRepository, whitelistRepository),
- trackersCount = when (app) {
- appListsRepository.dummySystemApp ->
- hiddenAppsTrackersWithWhiteList.size
- appListsRepository.dummyCompatibilityApp ->
- acAppsTrackersWithWhiteList.size
- else -> trackersCounts.getOrDefault(app, 0)
- },
- whiteListedTrackersCount = when (app) {
- appListsRepository.dummySystemApp ->
- hiddenAppsTrackersWithWhiteList.count { it.second }
- appListsRepository.dummyCompatibilityApp ->
- acAppsTrackersWithWhiteList.count { it.second }
- else ->
- getWhiteList(app).size
- },
- blockedLeaks = calls.first,
- leaks = calls.second
- )
- }
- .sortedWith(mostLeakedAppsComparator)
- }
- }
-
private fun getWhiteList(app: ApplicationDescription): List<Tracker> {
return whitelistRepository.getWhiteListForApp(app).mapNotNull {
trackersRepository.getTracker(it)
}
}
-
- private val mostLeakedAppsComparator: Comparator<AppWithCounts> = Comparator { o1, o2 ->
- val leaks = o2.leaks - o1.leaks
- if (leaks != 0) leaks else {
- val whitelisted = o2.whiteListedTrackersCount - o1.whiteListedTrackersCount
- if (whitelisted != 0) whitelisted else {
- o2.trackersCount - o1.trackersCount
- }
- }
- }
}