From f1d5b12dd11019508208571db5e5f57f43e3c4b6 Mon Sep 17 00:00:00 2001 From: Guillaume Jacquart Date: Mon, 2 Jan 2023 08:35:20 +0000 Subject: 5648: display trackers for pro-profile app instances. --- .../data/repositories/AppListsRepository.kt | 107 +++++++++++++-------- 1 file changed, 69 insertions(+), 38 deletions(-) (limited to 'app/src/main/java/foundation/e/privacycentralapp/data') 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 febda91..65ae478 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 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 E FOUNDATION + * Copyright (C) 2022 E FOUNDATION, 2022 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 @@ -21,11 +21,13 @@ import android.Manifest import android.content.Context import android.content.Intent import android.content.pm.ApplicationInfo -import android.content.pm.PackageManager +import android.content.pm.PackageInfo import foundation.e.privacycentralapp.R import foundation.e.privacymodules.permissions.PermissionsPrivacyModule import foundation.e.privacymodules.permissions.data.ApplicationDescription import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.map @@ -48,24 +50,67 @@ class AppListsRepository( icon = context.getDrawable(R.drawable.ic_e_app_logo) ) - fun getVisibleApps(): Flow> { - coroutineScope.launch { - val (visible, hidden) = splitVisibleToHidden(getAppsUsingInternet()) - appDescriptions.emit( - Pair( - visible.map { permissionsModule.buildApplicationDescription(it, withIcon = true) } + dummySystemApp, - hidden.map { permissionsModule.buildApplicationDescription(it, withIcon = false) }, - ) - ) + private suspend fun fetchAppDescriptions() { + val launcherPackageNames = pm.queryIntentActivities( + Intent(Intent.ACTION_MAIN, null).apply { addCategory(Intent.CATEGORY_LAUNCHER) }, + 0 + ).mapNotNull { it.activityInfo?.packageName } + + val visibleAppsFilter = { packageInfo: PackageInfo -> + hasInternetPermission(packageInfo) && + isNotHiddenSystemApp(packageInfo.applicationInfo, launcherPackageNames) + } + + val hiddenAppsFilter = { packageInfo: PackageInfo -> + hasInternetPermission(packageInfo) && + !isNotHiddenSystemApp(packageInfo.applicationInfo, launcherPackageNames) + } + + val visibleApps = permissionsModule.getApplications(visibleAppsFilter, true) + val hiddenApps = permissionsModule.getApplications(hiddenAppsFilter, false) + + val workProfileVisibleApps = permissionsModule.getWorkProfileApplications(visibleAppsFilter, true) + val workProfileHiddenApps = permissionsModule.getWorkProfileApplications(hiddenAppsFilter, false) + + appDescriptions.emit((visibleApps + dummySystemApp) to hiddenApps) + allProfilesAppDescriptions.emit( + (visibleApps + workProfileVisibleApps + dummySystemApp) + to (hiddenApps + workProfileHiddenApps) + ) + } + + private var refreshAppJob: Job? = null + private fun refreshAppDescriptions() { + if (refreshAppJob != null) { + return + } else { + refreshAppJob = coroutineScope.launch(Dispatchers.IO) { + fetchAppDescriptions() + refreshAppJob = null + } } + } + + fun getVisibleApps(): Flow> { + refreshAppDescriptions() return appDescriptions.map { it.first.sortedBy { app -> app.label.toString().lowercase() } } } + fun getHiddenSystemApps(): List { return appDescriptions.value.second } - fun getVisibleAndHiddenApps(): Flow> = getVisibleApps() - .map { it + getHiddenSystemApps() } + fun getAllProfilesVisibleApps(): Flow> { + refreshAppDescriptions() + return allProfilesAppDescriptions.map { it.first.sortedBy { app -> app.label.toString().lowercase() } } + } + + fun getAllProfilesHiddenSystemApps(): List { + return allProfilesAppDescriptions.value.second + } + + fun getAllApps(): Flow> = getAllProfilesVisibleApps() + .map { it + getAllProfilesHiddenSystemApps() } fun getApplicationDescription(packageName: String): ApplicationDescription? { return appDescriptions.value.first.find { it.packageName == packageName } @@ -77,7 +122,7 @@ class AppListsRepository( fun foldForHiddenSystemApp(appUid: Int, appValueGetter: (Int) -> Int): Int { return if (appUid == dummySystemApp.uid) { - getHiddenSystemApps().fold(0) { acc, app -> + getAllProfilesHiddenSystemApps().fold(0) { acc, app -> acc + appValueGetter(app.uid) } } else appValueGetter(appUid) @@ -92,14 +137,18 @@ class AppListsRepository( ) ) - private fun getAppsUsingInternet(): List { - return pm.getInstalledPackages(PackageManager.GET_PERMISSIONS).filter { - it.requestedPermissions?.contains(Manifest.permission.INTERNET) == true - }.map { - it.applicationInfo - } + private val allProfilesAppDescriptions = MutableStateFlow( + Pair( + emptyList(), + emptyList() + ) + ) + + private fun hasInternetPermission(packageInfo: PackageInfo): Boolean { + return packageInfo.requestedPermissions?.contains(Manifest.permission.INTERNET) == true } + @Suppress("ReturnCount") private fun isNotHiddenSystemApp(app: ApplicationInfo, launcherApps: List): Boolean { if (app.packageName == PNAME_SETTINGS) { return false @@ -116,22 +165,4 @@ class AppListsRepository( } private fun ApplicationInfo.hasFlag(flag: Int) = (flags and flag) == 1 - - private fun splitVisibleToHidden(apps: List): Pair, List> { - val launcherPackageNames = pm.queryIntentActivities( - Intent(Intent.ACTION_MAIN, null).apply { addCategory(Intent.CATEGORY_LAUNCHER) }, - 0 - ).mapNotNull { it.activityInfo?.packageName } - return apps.fold( - mutableListOf() to mutableListOf() - ) { - acc, app -> - if (isNotHiddenSystemApp(app, launcherPackageNames)) { - acc.first.add(app) - } else { - acc.second.add(app) - } - acc - } - } } -- cgit v1.2.3