summaryrefslogtreecommitdiff
path: root/app/src/main/java/foundation
diff options
context:
space:
mode:
authorjacquarg <guillaume.jacquart@hoodbrains.com>2022-02-28 09:30:55 +0100
committerjacquarg <guillaume.jacquart@hoodbrains.com>2022-03-01 10:06:22 +0100
commite9e22d2fdbde4e9679337fa681d60b3fdbfeace7 (patch)
tree17ee151ea3a5e5f90b8d48ecea88b78b6bb938f0 /app/src/main/java/foundation
parente6ba99e31da49df559da60e8d012e40813ee14f0 (diff)
Show trackers counts for each apps in tracekr screen, #4589
Diffstat (limited to 'app/src/main/java/foundation')
-rw-r--r--app/src/main/java/foundation/e/privacycentralapp/DependencyContainer.kt4
-rw-r--r--app/src/main/java/foundation/e/privacycentralapp/common/AppsAdapter.kt17
-rw-r--r--app/src/main/java/foundation/e/privacycentralapp/data/repositories/AppListsRepository.kt8
-rw-r--r--app/src/main/java/foundation/e/privacycentralapp/domain/entities/AppWithCounts.kt50
-rw-r--r--app/src/main/java/foundation/e/privacycentralapp/domain/usecases/TrackersStatisticsUseCase.kt23
-rw-r--r--app/src/main/java/foundation/e/privacycentralapp/features/trackers/TrackersFeature.kt57
-rw-r--r--app/src/main/java/foundation/e/privacycentralapp/features/trackers/TrackersFragment.kt6
-rw-r--r--app/src/main/java/foundation/e/privacycentralapp/features/trackers/TrackersViewModel.kt12
8 files changed, 124 insertions, 53 deletions
diff --git a/app/src/main/java/foundation/e/privacycentralapp/DependencyContainer.kt b/app/src/main/java/foundation/e/privacycentralapp/DependencyContainer.kt
index 76a9539..6b4035e 100644
--- a/app/src/main/java/foundation/e/privacycentralapp/DependencyContainer.kt
+++ b/app/src/main/java/foundation/e/privacycentralapp/DependencyContainer.kt
@@ -89,7 +89,7 @@ class DependencyContainer constructor(val app: Application) {
private val appListUseCase = AppListUseCase(appListsRepository)
private val trackersStatisticsUseCase by lazy {
- TrackersStatisticsUseCase(trackTrackersPrivacyModule, appListsRepository, context.resources)
+ TrackersStatisticsUseCase(trackTrackersPrivacyModule, blockTrackersPrivacyModule, appListsRepository, context.resources)
}
private val trackersStateUseCase by lazy {
@@ -119,7 +119,7 @@ class DependencyContainer constructor(val app: Application) {
}
val trackersViewModelFactory by lazy {
- TrackersViewModelFactory(trackersStatisticsUseCase, appListUseCase)
+ TrackersViewModelFactory(trackersStatisticsUseCase)
}
val appTrackersViewModelFactory by lazy {
diff --git a/app/src/main/java/foundation/e/privacycentralapp/common/AppsAdapter.kt b/app/src/main/java/foundation/e/privacycentralapp/common/AppsAdapter.kt
index d66ce76..07cf125 100644
--- a/app/src/main/java/foundation/e/privacycentralapp/common/AppsAdapter.kt
+++ b/app/src/main/java/foundation/e/privacycentralapp/common/AppsAdapter.kt
@@ -24,7 +24,7 @@ import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import foundation.e.privacycentralapp.R
-import foundation.e.privacymodules.permissions.data.ApplicationDescription
+import foundation.e.privacycentralapp.domain.entities.AppWithCounts
class AppsAdapter(
private val itemsLayout: Int,
@@ -34,15 +34,20 @@ class AppsAdapter(
class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val appName: TextView = view.findViewById(R.id.title)
-
- fun bind(item: ApplicationDescription) {
+ val counts: TextView = view.findViewById(R.id.counts)
+ val icon: ImageView = view.findViewById(R.id.icon)
+ fun bind(item: AppWithCounts) {
appName.text = item.label
-
- itemView.findViewById<ImageView>(R.id.icon).setImageDrawable(item.icon)
+ counts.text = itemView.context.getString(
+ R.string.trackers_app_trackers_counts,
+ item.blockedTrackersCount,
+ item.trackersCount
+ )
+ icon.setImageDrawable(item.icon)
}
}
- var dataSet: List<ApplicationDescription> = emptyList()
+ var dataSet: List<AppWithCounts> = emptyList()
set(value) {
field = value
notifyDataSetChanged()
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
index 4718923..958a536 100644
--- a/app/src/main/java/foundation/e/privacycentralapp/data/repositories/AppListsRepository.kt
+++ b/app/src/main/java/foundation/e/privacycentralapp/data/repositories/AppListsRepository.kt
@@ -50,6 +50,14 @@ class AppListsRepository(
return appDescriptions.value.second
}
+ fun foldForHiddenSystemApp(appUid: Int, appValueGetter: (Int) -> Int): Int {
+ return if (appUid == dummySystemApp.uid) {
+ getHiddenSystemApps().fold(0) { acc, app ->
+ acc + appValueGetter(app.uid)
+ }
+ } else appValueGetter(appUid)
+ }
+
private val pm get() = context.packageManager
private val appDescriptions = MutableStateFlow(
diff --git a/app/src/main/java/foundation/e/privacycentralapp/domain/entities/AppWithCounts.kt b/app/src/main/java/foundation/e/privacycentralapp/domain/entities/AppWithCounts.kt
new file mode 100644
index 0000000..682dfc8
--- /dev/null
+++ b/app/src/main/java/foundation/e/privacycentralapp/domain/entities/AppWithCounts.kt
@@ -0,0 +1,50 @@
+/*
+ * 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.domain.entities
+
+import android.graphics.drawable.Drawable
+import foundation.e.privacymodules.permissions.data.ApplicationDescription
+
+data class AppWithCounts(
+ val packageName: String,
+ val uid: Int,
+ var label: CharSequence?,
+ var icon: Drawable?,
+ val isWhitelisted: Boolean = false,
+ val trackersCount: Int = 0,
+ val whiteListedTrackersCount: Int = 0
+) {
+ constructor(
+ app: ApplicationDescription,
+ isWhitelisted: Boolean,
+ trackersCount: Int,
+ whiteListedTrackersCount: Int
+ ) :
+ this(
+ packageName = app.packageName,
+ uid = app.uid,
+ label = app.label,
+ icon = app.icon,
+ isWhitelisted = isWhitelisted,
+ trackersCount = trackersCount,
+ whiteListedTrackersCount = whiteListedTrackersCount
+ )
+
+ val blockedTrackersCount get() = if (isWhitelisted) 0
+ else trackersCount - whiteListedTrackersCount
+}
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 9a8b12a..ad8f565 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
@@ -20,18 +20,22 @@ 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.AppWithCounts
import foundation.e.privacycentralapp.domain.entities.TrackersPeriodicStatistics
+import foundation.e.privacymodules.trackers.IBlockTrackersPrivacyModule
import foundation.e.privacymodules.trackers.ITrackTrackersPrivacyModule
import foundation.e.privacymodules.trackers.Tracker
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
+import kotlinx.coroutines.flow.map
import java.time.ZonedDateTime
import java.time.format.DateTimeFormatter
import java.time.temporal.ChronoUnit
class TrackersStatisticsUseCase(
private val trackTrackersPrivacyModule: ITrackTrackersPrivacyModule,
+ private val blockTrackersPrivacyModule: IBlockTrackersPrivacyModule,
private val appListsRepository: AppListsRepository,
private val resources: Resources
) {
@@ -124,4 +128,23 @@ class TrackersStatisticsUseCase(
return trackers.sortedBy { it.label.lowercase() }
}
+
+ fun getAppsWithCounts(): Flow<List<AppWithCounts>> {
+ val trackersCounts = trackTrackersPrivacyModule.getTrackersCountByApp()
+ return appListsRepository.getVisibleApps()
+ .map { apps ->
+ apps.map { app ->
+ AppWithCounts(
+ app,
+ blockTrackersPrivacyModule.isWhitelisted(app.uid),
+ appListsRepository.foldForHiddenSystemApp(app.uid) {
+ trackersCounts.getOrDefault(it, 0)
+ },
+ appListsRepository.foldForHiddenSystemApp(app.uid) {
+ blockTrackersPrivacyModule.getWhiteList(it).size
+ }
+ )
+ }
+ }
+ }
}
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 e2eb58d..a606e49 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
@@ -22,11 +22,9 @@ import foundation.e.flowmvi.Actor
import foundation.e.flowmvi.Reducer
import foundation.e.flowmvi.SingleEventProducer
import foundation.e.flowmvi.feature.BaseFeature
+import foundation.e.privacycentralapp.domain.entities.AppWithCounts
import foundation.e.privacycentralapp.domain.entities.TrackersPeriodicStatistics
-import foundation.e.privacycentralapp.domain.usecases.AppListUseCase
import foundation.e.privacycentralapp.domain.usecases.TrackersStatisticsUseCase
-import foundation.e.privacymodules.permissions.data.ApplicationDescription
-import foundation.e.privacymodules.trackers.Tracker
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOf
@@ -52,13 +50,12 @@ class TrackersFeature(
val dayStatistics: TrackersPeriodicStatistics? = null,
val monthStatistics: TrackersPeriodicStatistics? = null,
val yearStatistics: TrackersPeriodicStatistics? = null,
- val apps: List<ApplicationDescription>? = null,
- val trackers: List<Tracker> = emptyList()
+ val apps: List<AppWithCounts>? = null,
)
sealed class SingleEvent {
data class ErrorEvent(val error: String) : SingleEvent()
- data class OpenAppDetailsEvent(val appDesc: ApplicationDescription) : SingleEvent()
+ data class OpenAppDetailsEvent(val appDesc: AppWithCounts) : SingleEvent()
object NewStatisticsAvailableSingleEvent : SingleEvent()
}
@@ -75,9 +72,9 @@ class TrackersFeature(
val yearStatistics: TrackersPeriodicStatistics? = null
) : Effect()
data class AvailableAppsListEffect(
- val apps: List<ApplicationDescription>
+ val apps: List<AppWithCounts>
) : Effect()
- data class OpenAppDetailsEffect(val appDesc: ApplicationDescription) : Effect()
+ data class OpenAppDetailsEffect(val appDesc: AppWithCounts) : Effect()
object QuickPrivacyDisabledWarningEffect : Effect()
data class ErrorEffect(val message: String) : Effect()
object NewStatisticsAvailablesEffect : Effect()
@@ -87,8 +84,7 @@ class TrackersFeature(
fun create(
initialState: State = State(),
coroutineScope: CoroutineScope,
- trackersStatisticsUseCase: TrackersStatisticsUseCase,
- appListUseCase: AppListUseCase
+ trackersStatisticsUseCase: TrackersStatisticsUseCase
) = TrackersFeature(
initialState, coroutineScope,
reducer = { state, effect ->
@@ -106,7 +102,19 @@ class TrackersFeature(
},
actor = { state, action ->
when (action) {
- Action.InitAction -> merge<TrackersFeature.Effect>(
+ Action.InitAction -> merge<Effect>(
+ flowOf(Effect.NewStatisticsAvailablesEffect),
+ trackersStatisticsUseCase.listenUpdates().map {
+ Effect.NewStatisticsAvailablesEffect
+ }
+ )
+
+ is Action.ClickAppAction -> flowOf(
+ state.apps?.find { it.packageName == action.packageName }?.let {
+ Effect.OpenAppDetailsEffect(it)
+ } ?: run { Effect.ErrorEffect("Can't find back app.") }
+ )
+ is Action.FetchStatistics -> merge<Effect>(
flow {
trackersStatisticsUseCase.getDayMonthYearStatistics()
.let { (day, month, year) ->
@@ -114,36 +122,15 @@ class TrackersFeature(
Effect.TrackersStatisticsLoadedEffect(
dayStatistics = day,
monthStatistics = month,
- yearStatistics = year
+ yearStatistics = year,
)
)
}
},
- appListUseCase.getAppsUsingInternet().map { apps ->
- Effect.AvailableAppsListEffect(apps)
- },
- trackersStatisticsUseCase.listenUpdates().map {
- Effect.NewStatisticsAvailablesEffect
+ trackersStatisticsUseCase.getAppsWithCounts().map {
+ Effect.AvailableAppsListEffect(it)
}
)
-
- is Action.ClickAppAction -> flowOf(
- state.apps?.find { it.packageName == action.packageName }?.let {
- Effect.OpenAppDetailsEffect(it)
- } ?: run { Effect.ErrorEffect("Can't find back app.") }
- )
- is Action.FetchStatistics -> flow {
- trackersStatisticsUseCase.getDayMonthYearStatistics()
- .let { (day, month, year) ->
- emit(
- Effect.TrackersStatisticsLoadedEffect(
- dayStatistics = day,
- monthStatistics = month,
- yearStatistics = year,
- )
- )
- }
- }
}
},
singleEventProducer = { _, _, effect ->
diff --git a/app/src/main/java/foundation/e/privacycentralapp/features/trackers/TrackersFragment.kt b/app/src/main/java/foundation/e/privacycentralapp/features/trackers/TrackersFragment.kt
index 3b22f89..0f686b4 100644
--- a/app/src/main/java/foundation/e/privacycentralapp/features/trackers/TrackersFragment.kt
+++ b/app/src/main/java/foundation/e/privacycentralapp/features/trackers/TrackersFragment.kt
@@ -18,10 +18,11 @@
package foundation.e.privacycentralapp.features.trackers
import android.os.Bundle
+import android.util.Log
import android.view.View
import android.widget.Toast
-import androidx.fragment.app.add
import androidx.fragment.app.commit
+import androidx.fragment.app.replace
import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
@@ -70,7 +71,7 @@ class TrackersFragment :
}
is TrackersFeature.SingleEvent.OpenAppDetailsEvent -> {
requireActivity().supportFragmentManager.commit {
- add<AppTrackersFragment>(R.id.container, args = AppTrackersFragment.buildArgs(event.appDesc.label.toString(), event.appDesc.packageName))
+ replace<AppTrackersFragment>(R.id.container, args = AppTrackersFragment.buildArgs(event.appDesc.label.toString(), event.appDesc.packageName))
setReorderingAllowed(true)
addToBackStack("apptrackers")
}
@@ -113,6 +114,7 @@ class TrackersFragment :
}
override fun onResume() {
+ Log.d("TestCounts", "OnResume")
super.onResume()
viewModel.submitAction(TrackersFeature.Action.FetchStatistics)
}
diff --git a/app/src/main/java/foundation/e/privacycentralapp/features/trackers/TrackersViewModel.kt b/app/src/main/java/foundation/e/privacycentralapp/features/trackers/TrackersViewModel.kt
index e3a97cc..c2a1822 100644
--- a/app/src/main/java/foundation/e/privacycentralapp/features/trackers/TrackersViewModel.kt
+++ b/app/src/main/java/foundation/e/privacycentralapp/features/trackers/TrackersViewModel.kt
@@ -20,15 +20,13 @@ package foundation.e.privacycentralapp.features.trackers
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import foundation.e.privacycentralapp.common.Factory
-import foundation.e.privacycentralapp.domain.usecases.AppListUseCase
import foundation.e.privacycentralapp.domain.usecases.TrackersStatisticsUseCase
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.launch
class TrackersViewModel(
- private val trackersStatisticsUseCase: TrackersStatisticsUseCase,
- private val appListUseCase: AppListUseCase
+ private val trackersStatisticsUseCase: TrackersStatisticsUseCase
) : ViewModel() {
private val _actions = MutableSharedFlow<TrackersFeature.Action>()
@@ -38,8 +36,7 @@ class TrackersViewModel(
TrackersFeature.create(
coroutineScope = viewModelScope,
- trackersStatisticsUseCase = trackersStatisticsUseCase,
- appListUseCase = appListUseCase
+ trackersStatisticsUseCase = trackersStatisticsUseCase
)
}
@@ -51,11 +48,10 @@ class TrackersViewModel(
}
class TrackersViewModelFactory(
- private val trackersStatisticsUseCase: TrackersStatisticsUseCase,
- private val appListUseCase: AppListUseCase
+ private val trackersStatisticsUseCase: TrackersStatisticsUseCase
) :
Factory<TrackersViewModel> {
override fun create(): TrackersViewModel {
- return TrackersViewModel(trackersStatisticsUseCase, appListUseCase)
+ return TrackersViewModel(trackersStatisticsUseCase)
}
}