summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorGuillaume Jacquart <guillaume.jacquart@hoodbrains.com>2022-03-01 08:06:11 +0000
committerGuillaume Jacquart <guillaume.jacquart@hoodbrains.com>2022-03-01 08:06:11 +0000
commited659e60de259fe51b811af96a589c6bb9fd7d35 (patch)
tree11a6458d30450420b7397560170579cfc857cded /app
parent13b6d0463fe7fa5cc5586b677e17d38a0fd5d0dd (diff)
parent41480b04ee31e8e694d370184c15de8c4dce03d0 (diff)
Merge branch 'hidden_system_app' into 'main'
Hide systems app behind parameter app in lists. See merge request e/privacy-central/privacycentralapp!19
Diffstat (limited to 'app')
-rw-r--r--app/build.gradle2
-rw-r--r--app/src/main/java/foundation/e/privacycentralapp/DependencyContainer.kt13
-rw-r--r--app/src/main/java/foundation/e/privacycentralapp/data/repositories/AppListsRepository.kt104
-rw-r--r--app/src/main/java/foundation/e/privacycentralapp/domain/usecases/AppListUseCase.kt103
-rw-r--r--app/src/main/java/foundation/e/privacycentralapp/domain/usecases/IpScramblingStateUseCase.kt40
-rw-r--r--app/src/main/java/foundation/e/privacycentralapp/domain/usecases/TrackersStateUseCase.kt31
-rw-r--r--app/src/main/java/foundation/e/privacycentralapp/domain/usecases/TrackersStatisticsUseCase.kt10
-rw-r--r--app/src/main/java/foundation/e/privacycentralapp/features/trackers/TrackersFeature.kt2
-rw-r--r--app/src/main/java/foundation/e/privacycentralapp/features/trackers/apptrackers/AppTrackersFeature.kt6
-rw-r--r--app/src/main/java/foundation/e/privacycentralapp/features/trackers/apptrackers/AppTrackersFragment.kt1
-rw-r--r--app/src/main/java/foundation/e/privacycentralapp/features/trackers/apptrackers/ToggleTrackersAdapter.kt9
-rw-r--r--app/src/main/res/layout/apptrackers_item_tracker_toggle.xml32
-rw-r--r--app/src/main/res/layout/item_app_toggle.xml16
13 files changed, 230 insertions, 139 deletions
diff --git a/app/build.gradle b/app/build.gradle
index 8812137..b771285 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -110,7 +110,7 @@ dependencies {
//googleImplementation project(":privacymodulesgoogle")
// include the e specific version of the modules, just for the e flavor
- implementation 'foundation.e:privacymodule.trackerfilter:0.2.0'
+ implementation 'foundation.e:privacymodule.trackerfilter:0.3.0'
implementation 'foundation.e:privacymodule.api:0.5.0'
e29Implementation 'foundation.e:privacymodule.e-29:0.4.2'
e30Implementation 'foundation.e:privacymodule.e-30:0.4.2'
diff --git a/app/src/main/java/foundation/e/privacycentralapp/DependencyContainer.kt b/app/src/main/java/foundation/e/privacycentralapp/DependencyContainer.kt
index c8d7fb2..76a9539 100644
--- a/app/src/main/java/foundation/e/privacycentralapp/DependencyContainer.kt
+++ b/app/src/main/java/foundation/e/privacycentralapp/DependencyContainer.kt
@@ -20,6 +20,7 @@ package foundation.e.privacycentralapp
import android.app.Application
import android.content.Context
import android.os.Process
+import foundation.e.privacycentralapp.data.repositories.AppListsRepository
import foundation.e.privacycentralapp.data.repositories.LocalStateRepository
import foundation.e.privacycentralapp.data.repositories.TrackersRepository
import foundation.e.privacycentralapp.domain.usecases.AppListUseCase
@@ -73,22 +74,26 @@ class DependencyContainer constructor(val app: Application) {
// 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
private val getQuickPrivacyStateUseCase by lazy {
GetQuickPrivacyStateUseCase(localStateRepository)
}
private val ipScramblingStateUseCase by lazy {
- IpScramblingStateUseCase(ipScramblerModule, permissionsModule, appDesc, localStateRepository, GlobalScope)
+ IpScramblingStateUseCase(
+ ipScramblerModule, permissionsModule, appDesc, localStateRepository,
+ appListsRepository, GlobalScope
+ )
}
- private val appListUseCase = AppListUseCase(permissionsModule, blockTrackersPrivacyModule, GlobalScope)
+ private val appListUseCase = AppListUseCase(appListsRepository)
private val trackersStatisticsUseCase by lazy {
- TrackersStatisticsUseCase(trackTrackersPrivacyModule, context.resources)
+ TrackersStatisticsUseCase(trackTrackersPrivacyModule, appListsRepository, context.resources)
}
private val trackersStateUseCase by lazy {
- TrackersStateUseCase(blockTrackersPrivacyModule, trackTrackersPrivacyModule, permissionsModule, localStateRepository, trackersRepository, GlobalScope)
+ TrackersStateUseCase(blockTrackersPrivacyModule, trackTrackersPrivacyModule, permissionsModule, localStateRepository, trackersRepository, appListsRepository, GlobalScope)
}
private val fakeLocationStateUseCase by lazy {
diff --git a/app/src/main/java/foundation/e/privacycentralapp/data/repositories/AppListsRepository.kt b/app/src/main/java/foundation/e/privacycentralapp/data/repositories/AppListsRepository.kt
new file mode 100644
index 0000000..4718923
--- /dev/null
+++ b/app/src/main/java/foundation/e/privacycentralapp/data/repositories/AppListsRepository.kt
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2022 E FOUNDATION
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package foundation.e.privacycentralapp.data.repositories
+
+import android.Manifest
+import android.content.Context
+import android.content.Intent
+import android.content.pm.ApplicationInfo
+import foundation.e.privacymodules.permissions.PermissionsPrivacyModule
+import foundation.e.privacymodules.permissions.data.ApplicationDescription
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.launch
+
+class AppListsRepository(
+ private val permissionsModule: PermissionsPrivacyModule,
+ private val context: Context,
+ private val coroutineScope: CoroutineScope
+) {
+ val dummySystemApp = permissionsModule.getApplicationDescription("com.android.settings")
+
+ fun getVisibleApps(): Flow<List<ApplicationDescription>> {
+ coroutineScope.launch {
+ val (visible, hidden) = splitVisibleToHidden(getAppsUsingInternet())
+ appDescriptions.emit(
+ visible.map { it.toApplicationDescription(withIcon = true) }
+ to hidden.map { it.toApplicationDescription() }
+ )
+ }
+ return appDescriptions.map { it.first.sortedBy { app -> app.label.toString().lowercase() } }
+ }
+ fun getHiddenSystemApps(): List<ApplicationDescription> {
+ return appDescriptions.value.second
+ }
+
+ private val pm get() = context.packageManager
+
+ private val appDescriptions = MutableStateFlow(
+ emptyList<ApplicationDescription>() to emptyList<ApplicationDescription>()
+ )
+
+ private fun getAppsUsingInternet(): List<ApplicationInfo> {
+ return pm.getInstalledApplications(0)
+ .filter {
+ permissionsModule.getPermissions(it.packageName)
+ .contains(Manifest.permission.INTERNET)
+ }
+ }
+
+ private fun isNotHiddenSystemApp(app: ApplicationInfo, launcherApps: List<String>): Boolean {
+ if (app.hasFlag(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)) {
+ return true
+ } else if (!app.hasFlag(ApplicationInfo.FLAG_SYSTEM)) {
+ return true
+ } else if (launcherApps.contains(app.packageName)) {
+ return true
+ }
+ return false
+ }
+
+ private fun ApplicationInfo.hasFlag(flag: Int) = (flags and flag) == 1
+
+ private fun splitVisibleToHidden(apps: List<ApplicationInfo>): Pair<List<ApplicationInfo>, List<ApplicationInfo>> {
+ val launcherPackageNames = pm.queryIntentActivities(
+ Intent(Intent.ACTION_MAIN, null).apply { addCategory(Intent.CATEGORY_LAUNCHER) },
+ 0
+ ).mapNotNull { it.activityInfo?.packageName }
+ return apps.fold(
+ mutableListOf<ApplicationInfo>() to mutableListOf<ApplicationInfo>()
+ ) {
+ acc, app ->
+ if (isNotHiddenSystemApp(app, launcherPackageNames)) {
+ acc.first.add(app)
+ } else {
+ acc.second.add(app)
+ }
+ acc
+ }
+ }
+
+ private fun ApplicationInfo.toApplicationDescription(withIcon: Boolean = true) = ApplicationDescription(
+ packageName = packageName,
+ uid = uid,
+ label = pm.getApplicationLabel(this),
+ icon = if (withIcon) pm.getApplicationIcon(packageName) else null
+ )
+}
diff --git a/app/src/main/java/foundation/e/privacycentralapp/domain/usecases/AppListUseCase.kt b/app/src/main/java/foundation/e/privacycentralapp/domain/usecases/AppListUseCase.kt
index acb8a36..4821349 100644
--- a/app/src/main/java/foundation/e/privacycentralapp/domain/usecases/AppListUseCase.kt
+++ b/app/src/main/java/foundation/e/privacycentralapp/domain/usecases/AppListUseCase.kt
@@ -17,112 +17,15 @@
package foundation.e.privacycentralapp.domain.usecases
-import android.Manifest
-import foundation.e.privacymodules.permissions.PermissionsPrivacyModule
+import foundation.e.privacycentralapp.data.repositories.AppListsRepository
import foundation.e.privacymodules.permissions.data.ApplicationDescription
-import foundation.e.privacymodules.trackers.api.BlockTrackersPrivacyModule
-import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.launch
class AppListUseCase(
- private val permissionsModule: PermissionsPrivacyModule,
- private val blockTrackersPrivacyModule: BlockTrackersPrivacyModule,
- private val corouteineScope: CoroutineScope
+ private val appListsRepository: AppListsRepository
) {
- private val _appsUsingInternet = MutableStateFlow<List<ApplicationDescription>>(emptyList())
- private val _appsBlockableTrackers = MutableStateFlow<List<ApplicationDescription>>(emptyList())
- init {
- corouteineScope.launch {
- _appsUsingInternet.value = getAppsUsingInternetList()
- }
- }
-
- fun getBlockableApps(): Flow<List<ApplicationDescription>> {
- corouteineScope.launch {
- _appsBlockableTrackers.value = getBlockableAppsList()
- }
- return _appsBlockableTrackers
- }
-
- private fun getBlockableAppsList(): List<ApplicationDescription> {
- return blockTrackersPrivacyModule.getBlockableApps()
- .filter {
- permissionsModule.getPermissions(it.packageName)
- .contains(Manifest.permission.INTERNET)
- }.map {
- it.icon = permissionsModule.getApplicationIcon(it.packageName)
- it
- }.sortedWith(object : Comparator<ApplicationDescription> {
- override fun compare(
- p0: ApplicationDescription?,
- p1: ApplicationDescription?
- ): Int {
- return if (p0?.icon != null && p1?.icon != null) {
- p0.label.toString().compareTo(p1.label.toString())
- } else if (p0?.icon == null) {
- 1
- } else {
- -1
- }
- }
- })
- }
-
- private fun getInstalledAppsUsingInternetList(): List<ApplicationDescription> {
- return permissionsModule.getInstalledApplications()
- .filter {
- permissionsModule.getPermissions(it.packageName)
- .contains(Manifest.permission.INTERNET)
- }.map {
- it.icon = permissionsModule.getApplicationIcon(it.packageName)
- it
- }.sortedWith(object : Comparator<ApplicationDescription> {
- override fun compare(
- p0: ApplicationDescription?,
- p1: ApplicationDescription?
- ): Int {
- return if (p0?.icon != null && p1?.icon != null) {
- p0.label.toString().compareTo(p1.label.toString())
- } else if (p0?.icon == null) {
- 1
- } else {
- -1
- }
- }
- })
- }
-
fun getAppsUsingInternet(): Flow<List<ApplicationDescription>> {
- corouteineScope.launch {
- _appsUsingInternet.value = getAppsUsingInternetList()
- }
- return _appsUsingInternet
- }
-
- private fun getAppsUsingInternetList(): List<ApplicationDescription> {
- return permissionsModule.getAllApplications()
- .filter {
- permissionsModule.getPermissions(it.packageName)
- .contains(Manifest.permission.INTERNET)
- }.map {
- it.icon = permissionsModule.getApplicationIcon(it.packageName)
- it
- }.sortedWith(object : Comparator<ApplicationDescription> {
- override fun compare(
- p0: ApplicationDescription?,
- p1: ApplicationDescription?
- ): Int {
- return if (p0?.icon != null && p1?.icon != null) {
- p0.label.toString().compareTo(p1.label.toString())
- } else if (p0?.icon == null) {
- 1
- } else {
- -1
- }
- }
- })
+ return appListsRepository.getVisibleApps()
}
}
diff --git a/app/src/main/java/foundation/e/privacycentralapp/domain/usecases/IpScramblingStateUseCase.kt b/app/src/main/java/foundation/e/privacycentralapp/domain/usecases/IpScramblingStateUseCase.kt
index 237e5b2..6cc8e4a 100644
--- a/app/src/main/java/foundation/e/privacycentralapp/domain/usecases/IpScramblingStateUseCase.kt
+++ b/app/src/main/java/foundation/e/privacycentralapp/domain/usecases/IpScramblingStateUseCase.kt
@@ -17,6 +17,7 @@
package foundation.e.privacycentralapp.domain.usecases
+import foundation.e.privacycentralapp.data.repositories.AppListsRepository
import foundation.e.privacycentralapp.data.repositories.LocalStateRepository
import foundation.e.privacycentralapp.domain.entities.InternetPrivacyMode
import foundation.e.privacymodules.ipscramblermodule.IIpScramblerModule
@@ -36,10 +37,10 @@ class IpScramblingStateUseCase(
private val permissionsPrivacyModule: IPermissionsPrivacyModule,
private val appDesc: ApplicationDescription,
private val localStateRepository: LocalStateRepository,
+ private val appListsRepository: AppListsRepository,
coroutineScope: CoroutineScope
) {
- // private val internetPrivacyModeMutableFlow = MutableStateFlow(InternetPrivacyMode.REAL_IP)
val internetPrivacyMode: StateFlow<InternetPrivacyMode> = callbackFlow {
val listener = object : IIpScramblerModule.Listener {
override fun onStatusChanged(newStatus: IIpScramblerModule.Status) {
@@ -79,16 +80,41 @@ class IpScramblingStateUseCase(
applySettings(true, hideIp)
}
- val bypassTorApps: Set<String> get() = ipScramblerModule.appList
+ private fun getHiddenPackageNames(): List<String> {
+ return appListsRepository.getHiddenSystemApps().map { it.packageName }
+ }
+
+ val bypassTorApps: Set<String> get() {
+ var whitelist = ipScramblerModule.appList
+
+ if (getHiddenPackageNames().any { it in whitelist }) {
+ val mutable = whitelist.toMutableSet()
+ mutable.removeAll(getHiddenPackageNames())
+ mutable.add(appListsRepository.dummySystemApp.packageName)
+ whitelist = mutable
+ }
+
+ return whitelist
+ }
fun toggleBypassTor(packageName: String) {
- val currentList = bypassTorApps.toMutableSet()
- if (currentList.contains(packageName)) {
- currentList.remove(packageName)
+ val visibleList = bypassTorApps.toMutableSet()
+ val rawList = ipScramblerModule.appList.toMutableSet()
+
+ if (visibleList.contains(packageName)) {
+ if (packageName == appListsRepository.dummySystemApp.packageName) {
+ rawList.removeAll(getHiddenPackageNames())
+ } else {
+ rawList.remove(packageName)
+ }
} else {
- currentList.add(packageName)
+ if (packageName == appListsRepository.dummySystemApp.packageName) {
+ rawList.addAll(getHiddenPackageNames())
+ } else {
+ rawList.add(packageName)
+ }
}
- ipScramblerModule.appList = currentList
+ ipScramblerModule.appList = rawList
}
private fun applySettings(isQuickPrivacyEnabled: Boolean, isIpScramblingEnabled: Boolean) {
diff --git a/app/src/main/java/foundation/e/privacycentralapp/domain/usecases/TrackersStateUseCase.kt b/app/src/main/java/foundation/e/privacycentralapp/domain/usecases/TrackersStateUseCase.kt
index e8759cb..16a1a82 100644
--- a/app/src/main/java/foundation/e/privacycentralapp/domain/usecases/TrackersStateUseCase.kt
+++ b/app/src/main/java/foundation/e/privacycentralapp/domain/usecases/TrackersStateUseCase.kt
@@ -17,6 +17,7 @@
package foundation.e.privacycentralapp.domain.usecases
+import foundation.e.privacycentralapp.data.repositories.AppListsRepository
import foundation.e.privacycentralapp.data.repositories.LocalStateRepository
import foundation.e.privacycentralapp.data.repositories.TrackersRepository
import foundation.e.privacymodules.permissions.PermissionsPrivacyModule
@@ -36,6 +37,7 @@ class TrackersStateUseCase(
private val permissionsPrivacyModule: PermissionsPrivacyModule,
private val localStateRepository: LocalStateRepository,
private val trackersRepository: TrackersRepository,
+ private val appListsRepository: AppListsRepository,
coroutineScope: CoroutineScope
) {
@@ -64,25 +66,44 @@ class TrackersStateUseCase(
blockTrackersPrivacyModule.isWhiteListEmpty()
}
- fun getApplicationPermission(packageName: String): ApplicationDescription {
+ fun getApplicationDescription(packageName: String): ApplicationDescription {
return permissionsPrivacyModule.getApplicationDescription(packageName)
}
fun isWhitelisted(appUid: Int): Boolean {
- return blockTrackersPrivacyModule.isWhitelisted(appUid)
+ return if (appUid == appListsRepository.dummySystemApp.uid) {
+ appListsRepository.getHiddenSystemApps().any {
+ blockTrackersPrivacyModule.isWhitelisted(it.uid)
+ }
+ } else blockTrackersPrivacyModule.isWhitelisted(appUid)
}
fun getTrackersWhitelistIds(appUid: Int): List<String> {
- return blockTrackersPrivacyModule.getWhiteList(appUid).map { it.id }
+ return if (appUid == appListsRepository.dummySystemApp.uid) {
+ appListsRepository.getHiddenSystemApps().fold(mutableSetOf<String>()) { acc, app ->
+ acc.addAll(blockTrackersPrivacyModule.getWhiteList(app.uid).map { it.id })
+ acc
+ }.toList()
+ } else blockTrackersPrivacyModule.getWhiteList(appUid).map { it.id }
}
fun toggleAppWhitelist(appUid: Int, isWhitelisted: Boolean) {
- blockTrackersPrivacyModule.setWhiteListed(appUid, isWhitelisted)
+ if (appUid == appListsRepository.dummySystemApp.uid) {
+ appListsRepository.getHiddenSystemApps().forEach {
+ blockTrackersPrivacyModule.setWhiteListed(it.uid, isWhitelisted)
+ }
+ } else blockTrackersPrivacyModule.setWhiteListed(appUid, isWhitelisted)
+
updateAllTrackersBlockedState()
}
fun blockTracker(appUid: Int, tracker: Tracker, isBlocked: Boolean) {
- blockTrackersPrivacyModule.setWhiteListed(tracker, appUid, !isBlocked)
+ if (appUid == appListsRepository.dummySystemApp.uid) {
+ appListsRepository.getHiddenSystemApps().forEach {
+ blockTrackersPrivacyModule.setWhiteListed(tracker, it.uid, !isBlocked)
+ }
+ } else blockTrackersPrivacyModule.setWhiteListed(tracker, appUid, !isBlocked)
+
updateAllTrackersBlockedState()
}
}
diff --git a/app/src/main/java/foundation/e/privacycentralapp/domain/usecases/TrackersStatisticsUseCase.kt b/app/src/main/java/foundation/e/privacycentralapp/domain/usecases/TrackersStatisticsUseCase.kt
index ad5c86c..9a8b12a 100644
--- a/app/src/main/java/foundation/e/privacycentralapp/domain/usecases/TrackersStatisticsUseCase.kt
+++ b/app/src/main/java/foundation/e/privacycentralapp/domain/usecases/TrackersStatisticsUseCase.kt
@@ -19,6 +19,7 @@ package foundation.e.privacycentralapp.domain.usecases
import android.content.res.Resources
import foundation.e.privacycentralapp.R
+import foundation.e.privacycentralapp.data.repositories.AppListsRepository
import foundation.e.privacycentralapp.domain.entities.TrackersPeriodicStatistics
import foundation.e.privacymodules.trackers.ITrackTrackersPrivacyModule
import foundation.e.privacymodules.trackers.Tracker
@@ -31,6 +32,7 @@ import java.time.temporal.ChronoUnit
class TrackersStatisticsUseCase(
private val trackTrackersPrivacyModule: ITrackTrackersPrivacyModule,
+ private val appListsRepository: AppListsRepository,
private val resources: Resources
) {
@@ -114,6 +116,12 @@ class TrackersStatisticsUseCase(
}
fun getTrackers(appUid: Int): List<Tracker> {
- return trackTrackersPrivacyModule.getTrackersForApp(appUid)
+ val trackers = if (appUid == appListsRepository.dummySystemApp.uid) {
+ appListsRepository.getHiddenSystemApps().map {
+ trackTrackersPrivacyModule.getTrackersForApp(it.uid)
+ }.flatten().distinctBy { it.id }
+ } else trackTrackersPrivacyModule.getTrackersForApp(appUid)
+
+ return trackers.sortedBy { it.label.lowercase() }
}
}
diff --git a/app/src/main/java/foundation/e/privacycentralapp/features/trackers/TrackersFeature.kt b/app/src/main/java/foundation/e/privacycentralapp/features/trackers/TrackersFeature.kt
index 00e3fb7..e2eb58d 100644
--- a/app/src/main/java/foundation/e/privacycentralapp/features/trackers/TrackersFeature.kt
+++ b/app/src/main/java/foundation/e/privacycentralapp/features/trackers/TrackersFeature.kt
@@ -119,7 +119,7 @@ class TrackersFeature(
)
}
},
- appListUseCase.getBlockableApps().map { apps ->
+ appListUseCase.getAppsUsingInternet().map { apps ->
Effect.AvailableAppsListEffect(apps)
},
trackersStatisticsUseCase.listenUpdates().map {
diff --git a/app/src/main/java/foundation/e/privacycentralapp/features/trackers/apptrackers/AppTrackersFeature.kt b/app/src/main/java/foundation/e/privacycentralapp/features/trackers/apptrackers/AppTrackersFeature.kt
index ff0c9db..16cd4a0 100644
--- a/app/src/main/java/foundation/e/privacycentralapp/features/trackers/apptrackers/AppTrackersFeature.kt
+++ b/app/src/main/java/foundation/e/privacycentralapp/features/trackers/apptrackers/AppTrackersFeature.kt
@@ -118,7 +118,7 @@ class AppTrackersFeature(
when (action) {
is Action.InitAction -> {
val appDesc =
- trackersStateUseCase.getApplicationPermission(action.packageName)
+ trackersStateUseCase.getApplicationDescription(action.packageName)
merge<Effect>(
flow {
@@ -154,9 +154,7 @@ class AppTrackersFeature(
emit(
Effect.AppTrackersBlockingActivatedEffect(
- !trackersStateUseCase.isWhitelisted(
- appUid
- )
+ !trackersStateUseCase.isWhitelisted(appUid)
)
)
}
diff --git a/app/src/main/java/foundation/e/privacycentralapp/features/trackers/apptrackers/AppTrackersFragment.kt b/app/src/main/java/foundation/e/privacycentralapp/features/trackers/apptrackers/AppTrackersFragment.kt
index 1f339ee..440edf7 100644
--- a/app/src/main/java/foundation/e/privacycentralapp/features/trackers/apptrackers/AppTrackersFragment.kt
+++ b/app/src/main/java/foundation/e/privacycentralapp/features/trackers/apptrackers/AppTrackersFragment.kt
@@ -97,7 +97,6 @@ class AppTrackersFragment :
super.onViewCreated(view, savedInstanceState)
binding = ApptrackersFragmentBinding.bind(view)
- // TODO: crash sqlite ?
binding.blockAllToggle.setOnClickListener {
viewModel.submitAction(Action.BlockAllToggleAction(binding.blockAllToggle.isChecked))
}
diff --git a/app/src/main/java/foundation/e/privacycentralapp/features/trackers/apptrackers/ToggleTrackersAdapter.kt b/app/src/main/java/foundation/e/privacycentralapp/features/trackers/apptrackers/ToggleTrackersAdapter.kt
index 0ab3987..580a60c 100644
--- a/app/src/main/java/foundation/e/privacycentralapp/features/trackers/apptrackers/ToggleTrackersAdapter.kt
+++ b/app/src/main/java/foundation/e/privacycentralapp/features/trackers/apptrackers/ToggleTrackersAdapter.kt
@@ -22,6 +22,7 @@ import android.view.View
import android.view.ViewGroup
import android.widget.Switch
import android.widget.TextView
+import androidx.core.view.isVisible
import androidx.recyclerview.widget.RecyclerView
import foundation.e.privacycentralapp.R
import foundation.e.privacymodules.trackers.Tracker
@@ -38,11 +39,13 @@ class ToggleTrackersAdapter(
val title: TextView = view.findViewById(R.id.title)
val toggle: Switch = view.findViewById(R.id.toggle)
+ val toggleOverlay: View = view.findViewById(R.id.toggle_clicker)
fun bind(item: Pair<Tracker, Boolean>, isEnabled: Boolean) {
title.text = item.first.label
toggle.isChecked = item.second
toggle.isEnabled = isEnabled
+ toggleOverlay.isVisible = !isEnabled
}
}
@@ -58,9 +61,13 @@ class ToggleTrackersAdapter(
val view = LayoutInflater.from(parent.context)
.inflate(itemsLayout, parent, false)
val holder = ViewHolder(view)
- holder.itemView.setOnClickListener {
+ holder.toggle.setOnClickListener {
listener(dataSet[holder.adapterPosition].first, holder.toggle.isChecked)
}
+ holder.toggleOverlay.setOnClickListener {
+ listener(dataSet[holder.adapterPosition].first, false)
+ }
+
return holder
}
diff --git a/app/src/main/res/layout/apptrackers_item_tracker_toggle.xml b/app/src/main/res/layout/apptrackers_item_tracker_toggle.xml
index baab3d9..20e0bdc 100644
--- a/app/src/main/res/layout/apptrackers_item_tracker_toggle.xml
+++ b/app/src/main/res/layout/apptrackers_item_tracker_toggle.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
-<androidx.appcompat.widget.LinearLayoutCompat
- xmlns:android="http://schemas.android.com/apk/res/android"
+<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/container"
android:layout_height="52dp"
android:layout_width="match_parent"
@@ -21,10 +21,28 @@
tools:text="Body sensor"
/>
- <Switch
- android:id="@+id/toggle"
+ <androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="wrap_content"
- android:layout_height="24dp"
- android:checked="true"
- />
+ android:layout_height="wrap_content">
+ <Switch
+ android:id="@+id/toggle"
+ android:layout_width="wrap_content"
+ android:layout_height="24dp"
+ android:checked="true"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ />
+ <View
+ android:id="@+id/toggle_clicker"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ android:clickable="true"
+ />
+ </androidx.constraintlayout.widget.ConstraintLayout>
</androidx.appcompat.widget.LinearLayoutCompat>
diff --git a/app/src/main/res/layout/item_app_toggle.xml b/app/src/main/res/layout/item_app_toggle.xml
index d0f565f..8bee0e2 100644
--- a/app/src/main/res/layout/item_app_toggle.xml
+++ b/app/src/main/res/layout/item_app_toggle.xml
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/item_permission_apps"
android:layout_height="wrap_content"
android:layout_width="match_parent"
@@ -34,11 +35,12 @@
tools:text="Body sensor"
/>
- <Switch
- android:id="@+id/toggle"
- android:layout_alignParentEnd="true"
- android:layout_centerVertical="true"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- />
+ <Switch
+ android:id="@+id/toggle"
+ android:layout_alignParentEnd="true"
+ android:layout_centerVertical="true"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ />
+
</RelativeLayout> \ No newline at end of file