summaryrefslogtreecommitdiff
path: root/app/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main')
-rw-r--r--app/src/main/java/foundation/e/privacycentralapp/common/AppsAdapter.kt3
-rw-r--r--app/src/main/java/foundation/e/privacycentralapp/data/repositories/AppListsRepository.kt4
-rw-r--r--app/src/main/java/foundation/e/privacycentralapp/domain/entities/AppWithCounts.kt12
-rw-r--r--app/src/main/java/foundation/e/privacycentralapp/domain/usecases/TrackersStatisticsUseCase.kt50
-rw-r--r--app/src/main/java/foundation/e/privacycentralapp/features/dashboard/DashboardFeature.kt60
-rw-r--r--app/src/main/java/foundation/e/privacycentralapp/features/dashboard/DashboardFragment.kt13
-rw-r--r--app/src/main/java/foundation/e/privacycentralapp/features/trackers/TrackersFeature.kt1
-rw-r--r--app/src/main/java/foundation/e/privacycentralapp/features/trackers/apptrackers/AppTrackersFeature.kt28
-rw-r--r--app/src/main/java/foundation/e/privacycentralapp/features/trackers/apptrackers/AppTrackersFragment.kt4
-rw-r--r--app/src/main/java/foundation/e/privacycentralapp/main/MainActivity.kt22
-rw-r--r--app/src/main/java/foundation/e/privacycentralapp/widget/Widget.kt19
-rw-r--r--app/src/main/java/foundation/e/privacycentralapp/widget/WidgetUI.kt15
-rw-r--r--app/src/main/res/layout/apptrackers_item_tracker_toggle.xml12
-rw-r--r--app/src/main/res/layout/fragment_dashboard.xml17
-rw-r--r--app/src/main/res/layout/widget.xml15
-rw-r--r--app/src/main/res/values-de/strings.xml10
-rw-r--r--app/src/main/res/values-fr/strings.xml2
-rw-r--r--app/src/main/res/values/strings.xml6
18 files changed, 216 insertions, 77 deletions
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 ed47cff..16b0144 100644
--- a/app/src/main/java/foundation/e/privacycentralapp/common/AppsAdapter.kt
+++ b/app/src/main/java/foundation/e/privacycentralapp/common/AppsAdapter.kt
@@ -41,7 +41,8 @@ class AppsAdapter(
counts.text = itemView.context.getString(
R.string.trackers_app_trackers_counts,
item.blockedTrackersCount,
- item.trackersCount
+ item.trackersCount,
+ item.leaks
)
icon.setImageDrawable(item.icon)
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 4b19083..1f23516 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
@@ -66,6 +66,10 @@ class AppListsRepository(
return appDescriptions.value.first.find { it.packageName == packageName }
}
+ fun getApplicationDescription(appUid: Int): ApplicationDescription? {
+ return appDescriptions.value.first.find { it.uid == appUid }
+ }
+
fun foldForHiddenSystemApp(appUid: Int, appValueGetter: (Int) -> Int): Int {
return if (appUid == dummySystemApp.uid) {
getHiddenSystemApps().fold(0) { acc, app ->
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
index 682dfc8..0b76c7b 100644
--- a/app/src/main/java/foundation/e/privacycentralapp/domain/entities/AppWithCounts.kt
+++ b/app/src/main/java/foundation/e/privacycentralapp/domain/entities/AppWithCounts.kt
@@ -27,13 +27,17 @@ data class AppWithCounts(
var icon: Drawable?,
val isWhitelisted: Boolean = false,
val trackersCount: Int = 0,
- val whiteListedTrackersCount: Int = 0
+ val whiteListedTrackersCount: Int = 0,
+ val blockedLeaks: Int = 0,
+ val leaks: Int = 0,
) {
constructor(
app: ApplicationDescription,
isWhitelisted: Boolean,
trackersCount: Int,
- whiteListedTrackersCount: Int
+ whiteListedTrackersCount: Int,
+ blockedLeaks: Int,
+ leaks: Int,
) :
this(
packageName = app.packageName,
@@ -42,7 +46,9 @@ data class AppWithCounts(
icon = app.icon,
isWhitelisted = isWhitelisted,
trackersCount = trackersCount,
- whiteListedTrackersCount = whiteListedTrackersCount
+ whiteListedTrackersCount = whiteListedTrackersCount,
+ blockedLeaks = blockedLeaks,
+ leaks = leaks
)
val blockedTrackersCount get() = if (isWhitelisted) 0
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 6b4e098..1fddb74 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
@@ -22,6 +22,7 @@ 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.permissions.data.ApplicationDescription
import foundation.e.privacymodules.trackers.IBlockTrackersPrivacyModule
import foundation.e.privacymodules.trackers.ITrackTrackersPrivacyModule
import foundation.e.privacymodules.trackers.Tracker
@@ -35,12 +36,14 @@ import java.time.format.DateTimeFormatter
import java.time.temporal.ChronoUnit
class TrackersStatisticsUseCase(
- // TODO private
- val trackTrackersPrivacyModule: ITrackTrackersPrivacyModule,
+ private val trackTrackersPrivacyModule: ITrackTrackersPrivacyModule,
private val blockTrackersPrivacyModule: IBlockTrackersPrivacyModule,
private val appListsRepository: AppListsRepository,
private val resources: Resources
) {
+ fun initAppList() {
+ appListsRepository.getVisibleApps()
+ }
fun listenUpdates(): Flow<Unit> = callbackFlow {
val listener = object : ITrackTrackersPrivacyModule.Listener {
@@ -60,6 +63,12 @@ class TrackersStatisticsUseCase(
) to trackTrackersPrivacyModule.getTrackersCount()
}
+ fun getMostLeakedApp(): ApplicationDescription? {
+ return appListsRepository.getApplicationDescription(
+ trackTrackersPrivacyModule.getPastDayMostLeakedApp()
+ )
+ }
+
fun getDayTrackersCalls() = trackTrackersPrivacyModule.getPastDayTrackersCalls()
fun getDayTrackersCount() = trackTrackersPrivacyModule.getPastDayTrackersCount()
@@ -136,26 +145,51 @@ class TrackersStatisticsUseCase(
return trackers.sortedBy { it.label.lowercase() }
}
+ fun getCalls(appUid: Int): Pair<Int, Int> {
+ return if (appUid == appListsRepository.dummySystemApp.uid) {
+ appListsRepository.getHiddenSystemApps().map {
+ trackTrackersPrivacyModule.getPastDayTrackersCallsForApp(it.uid)
+ }.reduce { (accBlocked, accLeaked), (blocked, leaked) ->
+ accBlocked + blocked to accLeaked + leaked
+ }
+ } else trackTrackersPrivacyModule.getPastDayTrackersCallsForApp(appUid)
+ }
+
fun getAppsWithCounts(): Flow<List<AppWithCounts>> {
val trackersCounts = trackTrackersPrivacyModule.getTrackersCountByApp()
+
return appListsRepository.getVisibleApps()
.map { apps ->
+ val callsByApp = trackTrackersPrivacyModule.getPastDayTrackersCallsByApps()
apps.map { app ->
+ val (blockedLeaks, leaks) = callsByApp.getOrDefault(app.uid, 0 to 0)
AppWithCounts(
- app,
- !blockTrackersPrivacyModule.isBlockingEnabled() ||
+ app = app,
+ isWhitelisted = !blockTrackersPrivacyModule.isBlockingEnabled() ||
blockTrackersPrivacyModule.isWhitelisted(app.uid),
- appListsRepository.foldForHiddenSystemApp(app.uid) {
+ trackersCount = appListsRepository.foldForHiddenSystemApp(app.uid) {
trackersCounts.getOrDefault(it, 0)
},
- appListsRepository.foldForHiddenSystemApp(app.uid) {
+ whiteListedTrackersCount = appListsRepository.foldForHiddenSystemApp(app.uid) {
blockTrackersPrivacyModule.getWhiteList(it).size
- }
+ },
+ blockedLeaks = blockedLeaks,
+ leaks = leaks
)
- }
+ }.sortedWith(mostLeakedAppsComparator)
}
}
+ 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
+ }
+ }
+ }
+
fun getNonBlockedTrackersCount(): Flow<Int> {
return if (blockTrackersPrivacyModule.isBlockingEnabled())
appListsRepository.getVisibleAndHiddenApps().map { apps ->
diff --git a/app/src/main/java/foundation/e/privacycentralapp/features/dashboard/DashboardFeature.kt b/app/src/main/java/foundation/e/privacycentralapp/features/dashboard/DashboardFeature.kt
index 3ed3168..5192229 100644
--- a/app/src/main/java/foundation/e/privacycentralapp/features/dashboard/DashboardFeature.kt
+++ b/app/src/main/java/foundation/e/privacycentralapp/features/dashboard/DashboardFeature.kt
@@ -27,6 +27,7 @@ import foundation.e.privacycentralapp.domain.entities.LocationMode
import foundation.e.privacycentralapp.domain.entities.QuickPrivacyState
import foundation.e.privacycentralapp.domain.usecases.GetQuickPrivacyStateUseCase
import foundation.e.privacycentralapp.domain.usecases.TrackersStatisticsUseCase
+import foundation.e.privacymodules.permissions.data.ApplicationDescription
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOf
@@ -66,6 +67,7 @@ class DashboardFeature(
object NavigateToInternetActivityPrivacySingleEvent : SingleEvent()
object NavigateToLocationSingleEvent : SingleEvent()
object NavigateToPermissionsSingleEvent : SingleEvent()
+ data class NavigateToAppDetailsEvent(val appDesc: ApplicationDescription) : SingleEvent()
object NewStatisticsAvailableSingleEvent : SingleEvent()
data class ToastMessageSingleEvent(val message: Int) : SingleEvent()
}
@@ -79,6 +81,7 @@ class DashboardFeature(
object ShowTrackers : Action()
object FetchStatistics : Action()
object CloseQuickPrivacyDisabledMessage : Action()
+ object ShowMostLeakedApp : Action()
}
sealed class Effect {
@@ -102,6 +105,7 @@ class DashboardFeature(
object FirstIPTrackerActivationEffect : Effect()
data class LocationHiddenUpdatedEffect(val isLocationHidden: Boolean) : Effect()
data class ShowQuickPrivacyDisabledMessageEffect(val show: Boolean) : Effect()
+ data class OpenAppDetailsEffect(val appDesc: ApplicationDescription) : Effect()
}
companion object {
@@ -146,29 +150,32 @@ class DashboardFeature(
}
}
- Action.InitAction -> merge(
- getPrivacyStateUseCase.quickPrivacyState.map {
- Effect.UpdateStateEffect(it)
- },
- getPrivacyStateUseCase.isIpHidden.map {
- Effect.IpScramblingModeUpdatedEffect(it)
- },
- trackersStatisticsUseCase.listenUpdates().map {
- Effect.NewStatisticsAvailablesEffect
- },
- getPrivacyStateUseCase.isTrackersDenied.map {
- Effect.TrackersBlockedUpdatedEffect(it)
- },
- getPrivacyStateUseCase.isLocationHidden.map {
- Effect.LocationHiddenUpdatedEffect(it)
- },
- getPrivacyStateUseCase.locationMode.map {
- Effect.UpdateLocationModeEffect(it)
- },
- getPrivacyStateUseCase.showQuickPrivacyDisabledMessage.map {
- Effect.ShowQuickPrivacyDisabledMessageEffect(it)
- },
- )
+ Action.InitAction -> {
+ trackersStatisticsUseCase.initAppList()
+ merge(
+ getPrivacyStateUseCase.quickPrivacyState.map {
+ Effect.UpdateStateEffect(it)
+ },
+ getPrivacyStateUseCase.isIpHidden.map {
+ Effect.IpScramblingModeUpdatedEffect(it)
+ },
+ trackersStatisticsUseCase.listenUpdates().map {
+ Effect.NewStatisticsAvailablesEffect
+ },
+ getPrivacyStateUseCase.isTrackersDenied.map {
+ Effect.TrackersBlockedUpdatedEffect(it)
+ },
+ getPrivacyStateUseCase.isLocationHidden.map {
+ Effect.LocationHiddenUpdatedEffect(it)
+ },
+ getPrivacyStateUseCase.locationMode.map {
+ Effect.UpdateLocationModeEffect(it)
+ },
+ getPrivacyStateUseCase.showQuickPrivacyDisabledMessage.map {
+ Effect.ShowQuickPrivacyDisabledMessageEffect(it)
+ },
+ )
+ }
Action.ShowFakeMyLocationAction -> flowOf(Effect.OpenFakeMyLocationEffect)
Action.ShowAppsPermissions -> flowOf(Effect.OpenAppsPermissionsEffect)
Action.ShowInternetActivityPrivacyAction -> flowOf(
@@ -193,6 +200,12 @@ class DashboardFeature(
getPrivacyStateUseCase.resetQuickPrivacyDisabledMessage()
flowOf(Effect.NoEffect)
}
+ is Action.ShowMostLeakedApp -> {
+ Log.d("mostleak", "Action.ShowMostLeakedApp")
+ flowOf(
+ trackersStatisticsUseCase.getMostLeakedApp()?.let { Effect.OpenAppDetailsEffect(appDesc = it) } ?: Effect.NoEffect
+ )
+ }
}
},
singleEventProducer = { _, _, effect ->
@@ -211,6 +224,7 @@ class DashboardFeature(
SingleEvent.ToastMessageSingleEvent(
message = R.string.dashboard_first_ipscrambling_activation
)
+ is Effect.OpenAppDetailsEffect -> SingleEvent.NavigateToAppDetailsEvent(effect.appDesc)
else -> null
}
}
diff --git a/app/src/main/java/foundation/e/privacycentralapp/features/dashboard/DashboardFragment.kt b/app/src/main/java/foundation/e/privacycentralapp/features/dashboard/DashboardFragment.kt
index 3f849a6..398a594 100644
--- a/app/src/main/java/foundation/e/privacycentralapp/features/dashboard/DashboardFragment.kt
+++ b/app/src/main/java/foundation/e/privacycentralapp/features/dashboard/DashboardFragment.kt
@@ -46,6 +46,7 @@ import foundation.e.privacycentralapp.features.dashboard.DashboardFeature.State
import foundation.e.privacycentralapp.features.internetprivacy.InternetPrivacyFragment
import foundation.e.privacycentralapp.features.location.FakeLocationFragment
import foundation.e.privacycentralapp.features.trackers.TrackersFragment
+import foundation.e.privacycentralapp.features.trackers.apptrackers.AppTrackersFragment
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.Flow
@@ -118,6 +119,13 @@ class DashboardFragment :
addToBackStack("dashboard")
}
}
+ is DashboardFeature.SingleEvent.NavigateToAppDetailsEvent -> {
+ requireActivity().supportFragmentManager.commit {
+ replace<AppTrackersFragment>(R.id.container, args = AppTrackersFragment.buildArgs(event.appDesc.label.toString(), event.appDesc.packageName))
+ setReorderingAllowed(true)
+ addToBackStack("dashboard")
+ }
+ }
DashboardFeature.SingleEvent.NewStatisticsAvailableSingleEvent -> {
viewModel.submitAction(DashboardFeature.Action.FetchStatistics)
}
@@ -138,6 +146,9 @@ class DashboardFragment :
graphHolder = GraphHolder(binding.graph, requireContext())
+ binding.leakingAppButton.setOnClickListener {
+ viewModel.submitAction(DashboardFeature.Action.ShowMostLeakedApp)
+ }
binding.togglePrivacyCentral.setOnClickListener {
viewModel.submitAction(DashboardFeature.Action.TogglePrivacyAction)
}
@@ -247,10 +258,12 @@ class DashboardFragment :
if (state.dayStatistics?.all { it.first == 0 && it.second == 0 } == true) {
binding.graph.visibility = View.INVISIBLE
binding.graphLegend.isVisible = false
+ binding.leakingAppButton.isVisible = false
binding.graphEmpty.isVisible = true
} else {
binding.graph.isVisible = true
binding.graphLegend.isVisible = true
+ binding.leakingAppButton.isVisible = true
binding.graphEmpty.isVisible = false
state.dayStatistics?.let { graphHolder.data = it }
state.dayLabels?.let { graphHolder.labels = it }
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 34ddfbe..25443e9 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
@@ -109,7 +109,6 @@ class TrackersFeature(
actor = { state, action ->
when (action) {
Action.InitAction -> merge<Effect>(
- flowOf(Effect.NewStatisticsAvailablesEffect),
trackersStatisticsUseCase.listenUpdates().map {
Effect.NewStatisticsAvailablesEffect
},
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 ad82337..f6d7d67 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
@@ -55,8 +55,10 @@ class AppTrackersFeature(
val isBlockingActivated: Boolean = false,
val trackers: List<Tracker>? = null,
val whitelist: List<String>? = null,
+ val leaked: Int = 0,
+ val blocked: Int = 0,
val isQuickPrivacyEnabled: Boolean = false,
- val showQuickPrivacyDisabledMessage: Boolean = false
+ val showQuickPrivacyDisabledMessage: Boolean = false,
) {
fun getTrackersStatus(): List<Pair<Tracker, Boolean>>? {
if (trackers != null && whitelist != null) {
@@ -92,7 +94,11 @@ class AppTrackersFeature(
data class ErrorEffect(val message: Any) : Effect()
data class SetAppEffect(val appDesc: ApplicationDescription) : Effect()
data class AppTrackersBlockingActivatedEffect(val isBlockingActivated: Boolean) : Effect()
- data class AvailableTrackersListEffect(val trackers: List<Tracker>) : Effect()
+ data class AvailableTrackersListEffect(
+ val trackers: List<Tracker>,
+ val blocked: Int,
+ val leaked: Int
+ ) : Effect()
data class TrackersWhitelistUpdateEffect(val whitelist: List<String>) : Effect()
object NewStatisticsAvailablesEffect : Effect()
data class QuickPrivacyUpdatedEffect(val enabled: Boolean) : Effect()
@@ -114,7 +120,11 @@ class AppTrackersFeature(
reducer = { state, effect ->
when (effect) {
is Effect.SetAppEffect -> state.copy(appDesc = effect.appDesc)
- is Effect.AvailableTrackersListEffect -> state.copy(trackers = effect.trackers)
+ is Effect.AvailableTrackersListEffect -> state.copy(
+ trackers = effect.trackers,
+ leaked = effect.leaked,
+ blocked = effect.blocked
+ )
is Effect.AppTrackersBlockingActivatedEffect ->
state.copy(isBlockingActivated = effect.isBlockingActivated)
@@ -135,7 +145,6 @@ class AppTrackersFeature(
.getApplicationDescription(action.packageName)?.let { appDesc ->
merge<Effect>(
flow {
-
emit(Effect.SetAppEffect(appDesc))
emit(
Effect.AppTrackersBlockingActivatedEffect(
@@ -147,11 +156,6 @@ class AppTrackersFeature(
trackersStateUseCase.getTrackersWhitelistIds(appDesc.uid)
)
)
- emit(
- Effect.AvailableTrackersListEffect(
- trackers = trackersStatisticsUseCase.getTrackers(appDesc.uid)
- )
- )
},
trackersStatisticsUseCase.listenUpdates().map {
Effect.NewStatisticsAvailablesEffect
@@ -208,8 +212,12 @@ class AppTrackersFeature(
}
is Action.FetchStatistics -> flowOf(
state.appDesc?.uid?.let {
+ val (blocked, leaked) = trackersStatisticsUseCase.getCalls(it)
+
Effect.AvailableTrackersListEffect(
- trackers = trackersStatisticsUseCase.getTrackers(it)
+ trackers = trackersStatisticsUseCase.getTrackers(it),
+ leaked = leaked,
+ blocked = blocked,
)
} ?: Effect.ErrorEffect("No appDesc.")
)
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 7e606af..406d26c 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
@@ -143,7 +143,9 @@ class AppTrackersFragment :
else getString(
R.string.apptrackers_trackers_count_summary,
state.getBlockedTrackersCount(),
- state.getTrackersCount()
+ state.getTrackersCount(),
+ state.blocked,
+ state.leaked
)
binding.blockAllToggle.isChecked = state.isBlockingActivated
diff --git a/app/src/main/java/foundation/e/privacycentralapp/main/MainActivity.kt b/app/src/main/java/foundation/e/privacycentralapp/main/MainActivity.kt
index 5159827..92a156a 100644
--- a/app/src/main/java/foundation/e/privacycentralapp/main/MainActivity.kt
+++ b/app/src/main/java/foundation/e/privacycentralapp/main/MainActivity.kt
@@ -27,21 +27,11 @@ import androidx.fragment.app.commit
import foundation.e.privacycentralapp.PrivacyCentralApplication
import foundation.e.privacycentralapp.R
import foundation.e.privacycentralapp.features.dashboard.DashboardFragment
+import foundation.e.privacycentralapp.features.trackers.TrackersFragment
import kotlinx.coroutines.FlowPreview
@FlowPreview
open class MainActivity : FragmentActivity(R.layout.activity_main) {
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- if (savedInstanceState == null) {
- supportFragmentManager.commit {
- setReorderingAllowed(true)
- add<DashboardFragment>(R.id.container)
- }
- }
- }
-
override fun onPostCreate(savedInstanceState: Bundle?) {
super.onPostCreate(savedInstanceState)
handleIntent(intent)
@@ -65,6 +55,10 @@ open class MainActivity : FragmentActivity(R.layout.activity_main) {
containerViewId = R.id.container,
args = intent.extras
)
+ ACTION_VIEW_TRACKERS -> {
+ add<TrackersFragment>(R.id.container)
+ addToBackStack("dashboard")
+ }
else -> add<DashboardFragment>(R.id.container)
}
}
@@ -82,11 +76,17 @@ open class MainActivity : FragmentActivity(R.layout.activity_main) {
companion object {
private const val ACTION_HIGHLIGHT_LEAKS = "ACTION_HIGHLIGHT_LEAKS"
+ private const val ACTION_VIEW_TRACKERS = "ACTION_VIEW_TRACKERS"
fun createHighlightLeaksIntent(context: Context, highlightIndex: Int) =
Intent(context, MainActivity::class.java).apply {
action = ACTION_HIGHLIGHT_LEAKS
putExtras(DashboardFragment.buildArgs(highlightIndex))
}
+
+ fun createTrackersIntent(context: Context) =
+ Intent(context, MainActivity::class.java).apply {
+ action = ACTION_VIEW_TRACKERS
+ }
}
}
diff --git a/app/src/main/java/foundation/e/privacycentralapp/widget/Widget.kt b/app/src/main/java/foundation/e/privacycentralapp/widget/Widget.kt
index 7efb6b0..6fd9470 100644
--- a/app/src/main/java/foundation/e/privacycentralapp/widget/Widget.kt
+++ b/app/src/main/java/foundation/e/privacycentralapp/widget/Widget.kt
@@ -29,16 +29,20 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
+import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.debounce
+import kotlinx.coroutines.flow.flow
+import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.sample
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
+import java.time.temporal.ChronoUnit
/**
* Implementation of App Widget functionality.
@@ -88,9 +92,18 @@ class Widget : AppWidgetProvider() {
)
}.sample(50)
.combine(
- trackersStatisticsUseCase.listenUpdates()
- .onStart { emit(Unit) }
- .debounce(5000)
+ merge(
+ trackersStatisticsUseCase.listenUpdates()
+ .onStart { emit(Unit) }
+ .debounce(5000),
+ flow {
+ while (true) {
+ emit(Unit)
+ delay(ChronoUnit.HOURS.duration.toMillis())
+ }
+ }
+
+ )
) { state, _ ->
state.copy(
dayStatistics = trackersStatisticsUseCase.getDayTrackersCalls(),
diff --git a/app/src/main/java/foundation/e/privacycentralapp/widget/WidgetUI.kt b/app/src/main/java/foundation/e/privacycentralapp/widget/WidgetUI.kt
index 81859e6..ca93617 100644
--- a/app/src/main/java/foundation/e/privacycentralapp/widget/WidgetUI.kt
+++ b/app/src/main/java/foundation/e/privacycentralapp/widget/WidgetUI.kt
@@ -127,11 +127,23 @@ fun render(
setViewVisibility(R.id.graph_legend, View.GONE)
setViewVisibility(R.id.graph_empty, View.VISIBLE)
setViewVisibility(R.id.graph_legend_values, View.GONE)
+ setViewVisibility(R.id.graph_view_trackers_btn, View.GONE)
} else {
setViewVisibility(R.id.graph, View.VISIBLE)
setViewVisibility(R.id.graph_legend, View.VISIBLE)
setViewVisibility(R.id.graph_empty, View.GONE)
setViewVisibility(R.id.graph_legend_values, View.VISIBLE)
+ setViewVisibility(R.id.graph_view_trackers_btn, View.VISIBLE)
+
+ val pIntent = PendingIntent.getActivity(
+ context,
+ REQUEST_CODE_TRACKERS,
+ MainActivity.createTrackersIntent(context),
+ FLAG_UPDATE_CURRENT
+ )
+
+ setOnClickPendingIntent(R.id.graph_view_trackers_btn, pIntent)
+ // setOnClickPendingIntent(R.id.graph_view_trackers_btn_icon, pIntent)
val graphHeightPx = 26.dpToPxF(context)
val maxValue =
@@ -146,7 +158,7 @@ fun render(
val middlePadding = graphHeightPx - blocked * ratio
setViewPadding(blockedBarIds[index], 0, middlePadding.toInt(), 0, 0)
- // leacked (the bar above)
+ // leaked (the bar above)
val topPadding = graphHeightPx - (blocked + leaked) * ratio
setViewPadding(leakedBarIds[index], 0, topPadding.toInt(), 0, 0)
@@ -254,4 +266,5 @@ private val leakedBarIds = listOf(
private const val REQUEST_CODE_DASHBOARD = 1
private const val REQUEST_CODE_TOGGLE = 2
+private const val REQUEST_CODE_TRACKERS = 3
private const val REQUEST_CODE_HIGHLIGHT = 100
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 0371390..db7086f 100644
--- a/app/src/main/res/layout/apptrackers_item_tracker_toggle.xml
+++ b/app/src/main/res/layout/apptrackers_item_tracker_toggle.xml
@@ -20,10 +20,10 @@
android:textSize="14sp"
tools:text="Body sensor"
/>
- <Switch
- android:id="@+id/toggle"
- android:layout_width="wrap_content"
- android:layout_height="24dp"
- android:checked="true"
- />
+ <Switch
+ android:id="@+id/toggle"
+ android:layout_width="wrap_content"
+ android:layout_height="24dp"
+ android:checked="true"
+ />
</androidx.appcompat.widget.LinearLayoutCompat>
diff --git a/app/src/main/res/layout/fragment_dashboard.xml b/app/src/main/res/layout/fragment_dashboard.xml
index d79dea1..f6beca6 100644
--- a/app/src/main/res/layout/fragment_dashboard.xml
+++ b/app/src/main/res/layout/fragment_dashboard.xml
@@ -30,7 +30,7 @@
android:layout_height="25dp"
android:layout_width="24dp"
android:layout_margin="16dp"
- android:src="@drawable/ic_shield_off"
+ android:src="@drawable/ic_shield_off_white"
android:scaleType="fitCenter"
/>
<TextView
@@ -248,6 +248,21 @@ android:text="@string/dashboard_state_ipaddress_off"
/>
<TextView
+ android:id="@+id/leaking_app_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="12sp"
+ android:textColor="@color/primary_text"
+ android:drawableEnd="@drawable/ic_chevron_right_24dp"
+ android:text="@string/dashboard_graph_leaking_app"
+ app:layout_constraintRight_toRightOf="parent"
+ app:layout_constraintBottom_toBottomOf="@+id/graph_legend_blocked_icon"
+ app:layout_constraintTop_toTopOf="@+id/graph_legend_blocked_icon"
+ android:gravity="center_vertical|end"
+ android:layout_marginRight="16dp"
+ />
+
+ <TextView
android:id="@+id/graph_empty"
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/app/src/main/res/layout/widget.xml b/app/src/main/res/layout/widget.xml
index e55d8a3..999a888 100644
--- a/app/src/main/res/layout/widget.xml
+++ b/app/src/main/res/layout/widget.xml
@@ -687,6 +687,7 @@
android:layout_marginTop="16dp"
android:layout_marginHorizontal="24dp"
android:layout_marginBottom="24dp"
+ android:gravity="center_vertical"
>
<ImageView
@@ -726,6 +727,20 @@
android:textSize="12sp"
android:text="@string/graph_legend_allowed"
/>
+
+ <TextView
+ android:id="@+id/graph_view_trackers_btn"
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_height="wrap_content"
+ android:textSize="12sp"
+ android:textAlignment="textEnd"
+ android:gravity="center_vertical|end"
+ android:textColor="@color/on_primary_high_emphasis"
+ android:drawableEnd="@drawable/ic_chevron_right_24dp"
+ android:drawableTint="@color/on_primary_high_emphasis"
+ android:text="@string/widget_graph_view_trackers"
+ />
</LinearLayout>
<TextView
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index e89904a..b598588 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -9,11 +9,11 @@
<string name="dashboard_state_geolocation_on">Gefälscht</string>
<string name="dashboard_state_ipaddress_label">Echte IP-Adresse:</string>
<string name="dashboard_state_ipaddress_on">Versteckt</string>
- <string name="dashboard_graph_label">Durchsickern persönlicher Daten</string>
+ <string name="dashboard_graph_label">Durchsickern persönlicher Daten:</string>
<string name="dashboard_graph_period">Heute</string>
<string name="dashboard_graph_trackers_legend">%s Tracker haben dich in den letzten 24 Stunden aufgezeichnet</string>
<string name="dashboard_am_i_tracked_title">Verwalte die Tracker von Apps</string>
- <string name="dashboard_am_i_tracked_subtitle">%1$d App-Tracker, %2$d aktive Tracker</string>
+ <string name="dashboard_am_i_tracked_subtitle">%1$d App-Tracker, %2$d erlaubte Tracker</string>
<string name="dashboard_apps_permissions_title">Verwalte App-Berechtigungen</string>
<string name="dashboard_apps_permissions_subtitle">Verwalte deine Berechtigungen</string>
<string name="dashboard_location_title">Verwalte dein Standort</string>
@@ -76,9 +76,7 @@
<string name="add_widget">Widget hinzufügen</string>
<string name="add_location">Standort hinzufügen</string>
<string name="dummy_system_app_label">System</string>
- <string name="trackers_info">Tracker (Verfolger) sind kleine Programme, die in Anwendungen eingebaut werden. Sie sammeln deine Daten und verfolgen andauernd deine Aktivität: wie als ob dein Telefon dich ständig überwachen würde.
-\n
-\nDu kannst sehen, wie viele Tracker im Hintergrund aktiv sind, und du kannst diese Tracker für den best möglichsten Schutz blockieren. Das kann aber auch manche Apps am korrekten Funktionieren hindern, darum kannst du die Einstellungen selbst anpassen und auswählen, welche Tracker du blockieren möchtest.</string>
+ <string name="trackers_info">Tracker (Verfolger) sind kleine Programme, die in Anwendungen eingebaut werden. Sie sammeln deine Daten und verfolgen andauernd deine Aktivität. Du kannst sehen, wie viele Tracker aktiv sind, und kannst sie alle für den bestmöglichen Schutz blockieren. Das kann aber auch manche Apps am korrekten Funktionieren hindern, darum kannst du selbst auswählen, welche Tracker du blockieren möchtest.</string>
<string name="trackers_count_label">%d Tracker</string>
<string name="trackers_period_day">24 Stunden</string>
<string name="trackers_period_month">vergangener Monat</string>
@@ -116,4 +114,6 @@
<string name="dashboard_state_title_custom">Benutzerdefinierte Datenschutz-Einstellungen werden angewendet</string>
<string name="quickprivacy_disabled_message">Die Änderungen werden erst beim Aktivieren des Datenschutz-Schalters angewandt.</string>
<string name="close">Schließen</string>
+ <string name="dashboard_first_ipscrambling_activation">Während des Fälschens deiner IP wird die Internetgeschwindigkeit möglicherweise verlangsamt.</string>
+ <string name="widget_state_title_custom">Benutzerdefinierte Datenschutz-Einstellungen werden angewandt</string>
</resources> \ No newline at end of file
diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml
index 47970a1..c0a8582 100644
--- a/app/src/main/res/values-fr/strings.xml
+++ b/app/src/main/res/values-fr/strings.xml
@@ -62,7 +62,7 @@
<string name="trackers_title">Gérer les pisteurs des applications</string>
<string name="trackers_count_label">%d pisteurs</string>
<string name="trackers_applist_title">Gérer les pisteurs utilisés dans les applications :</string>
- <string name="trackers_app_trackers_counts">%1$d pisteurs bloqués sur %2$d</string>
+ <string name="trackers_app_trackers_counts">%1$d pisteurs bloqués sur %2$d, </string>
<string name="apptrackers_block_all_toggle">Bloquer les pisteurs</string>
<string name="apptrackers_trackers_list_title">Optez pour les pisteurs que vous souhaitez activer/désactiver.</string>
<string name="apptrackers_no_trackers_yet_block_off">Pour l\'instant, aucun pisteurs n\'a été détecté. Si de nouveaux pisteurs sont détectés, ils seront mis à jour ici.</string>
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 489dff2..c1f15f0 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -27,6 +27,7 @@
<string name="dashboard_graph_label">Personal data leakage:</string>
<string name="dashboard_graph_period">Today</string>
<string name="dashboard_graph_trackers_legend">%s trackers have profiled you in the last 24 hours</string>
+ <string name="dashboard_graph_leaking_app">View</string>
<string name="dashboard_first_ipscrambling_activation">While your IP is faked, your internet speed is likely to be reduced.</string>
<string name="dashboard_am_i_tracked_title">Manage apps\' trackers</string>
@@ -77,7 +78,7 @@
<string name="trackers_graph_hours_period_format">HH:mm</string>
<string name="trackers_graph_days_period_format">MMMM d - EEE</string>
<string name="trackers_graph_months_period_format">MMMM yyyy</string>
- <string name="trackers_app_trackers_counts">%1$d blocked trackers out of %2$d</string>
+ <string name="trackers_app_trackers_counts">%1$d blocked trackers out of %2$d, %3$d leaks</string>
<!-- App Trackers -->
<string name="apptrackers_block_all_toggle">Block trackers</string>
@@ -85,7 +86,7 @@
<string name="apptrackers_no_trackers_yet_block_off">No trackers were detected yet. If new trackers are detected they will be updated here.</string>
<string name="apptrackers_no_trackers_yet_block_on">No trackers were detected yet. All future trackers will be blocked.</string>
<string name="apptrackers_error_quickprivacy_disabled">Enable Quick Privacy to be able to activate/deactivate trackers.</string>
- <string name="apptrackers_trackers_count_summary">%1$d blocked trackers out of %2$d detected trackers</string>
+ <string name="apptrackers_trackers_count_summary">%1$d blocked trackers out of %2$d detected trackers, %3$d blocked leaks and %4$d allowed leaks.</string>
<string name="apptrackers_error_no_app">App not installed.</string>
<!-- -->
@@ -140,6 +141,7 @@
<string name="widget_state_ipaddress_off">@string/dashboard_state_ipaddress_off</string>
<string name="widget_state_ipaddress_on">@string/dashboard_state_ipaddress_on</string>
<string name="widget_graph_trackers_legend">@string/dashboard_graph_trackers_legend</string>
+ <string name="widget_graph_view_trackers">View</string>
<string name="first_notification_title">Discover Advanced Privacy</string>
<string name="first_notification_summary">Tap to find out how to easily block trackers, fake your location &amp; hide your IP address.</string>