diff --git a/app/src/main/java/eu/darken/myperm/apps/core/AppRepo.kt b/app/src/main/java/eu/darken/myperm/apps/core/AppRepo.kt index 35760076..2fc8cb01 100644 --- a/app/src/main/java/eu/darken/myperm/apps/core/AppRepo.kt +++ b/app/src/main/java/eu/darken/myperm/apps/core/AppRepo.kt @@ -4,6 +4,7 @@ import android.content.Context import dagger.hilt.android.qualifiers.ApplicationContext import eu.darken.myperm.apps.core.container.* import eu.darken.myperm.apps.core.known.AKnownPkg +import eu.darken.myperm.common.IPCFunnel import eu.darken.myperm.common.coroutine.AppScope import eu.darken.myperm.common.coroutine.DispatcherProvider import eu.darken.myperm.common.debug.logging.Logging.Priority.ERROR @@ -28,6 +29,7 @@ class AppRepo @Inject constructor( @AppScope private val appScope: CoroutineScope, private val dispatcherProvider: DispatcherProvider, packageEventListener: PackageEventListener, + private val ipcFunnel: IPCFunnel, ) { private val refreshTrigger = MutableStateFlow(UUID.randomUUID()) @@ -48,7 +50,7 @@ class AppRepo @Inject constructor( val pkgs = coroutineScope { val normal = async(dispatcherProvider.Default) { measureTimedValue { - getNormalPkgs(context) + getNormalPkgs(ipcFunnel) }.let { log(TAG) { "Perf: Primary profile pkgs took ${it.duration.inWholeMilliseconds}ms" } it.value @@ -56,7 +58,7 @@ class AppRepo @Inject constructor( } val secondaryProfile = async(dispatcherProvider.Default) { measureTimedValue { - getSecondaryProfilePkgs(context) + getSecondaryProfilePkgs(ipcFunnel) }.let { log(TAG) { "Perf: Secondary profile pkgs took ${it.duration.inWholeMilliseconds}ms" } it.value @@ -64,7 +66,7 @@ class AppRepo @Inject constructor( } val uninstalledPkgs = async(dispatcherProvider.Default) { measureTimedValue { - getSecondaryUserPkgs(context).filter { uninstalled -> + getSecondaryUserPkgs(ipcFunnel).filter { uninstalled -> secondaryProfile.await().none { it.id.pkgName == uninstalled.id.pkgName } } }.let { diff --git a/app/src/main/java/eu/darken/myperm/apps/core/PackageManagerExtensions.kt b/app/src/main/java/eu/darken/myperm/apps/core/PackageManagerExtensions.kt index d3d5218b..34827cae 100644 --- a/app/src/main/java/eu/darken/myperm/apps/core/PackageManagerExtensions.kt +++ b/app/src/main/java/eu/darken/myperm/apps/core/PackageManagerExtensions.kt @@ -48,7 +48,7 @@ fun PackageManager.getPermissionInfo2( null } -val PackageManager.GET_UNINSTALLED_PACKAGES_COMPAT +val GET_UNINSTALLED_PACKAGES_COMPAT: Int get() = when { hasApiLevel(Build.VERSION_CODES.N) -> PackageManager.MATCH_UNINSTALLED_PACKAGES else -> PackageManager.GET_UNINSTALLED_PACKAGES diff --git a/app/src/main/java/eu/darken/myperm/apps/core/container/PrimaryProfilePkg.kt b/app/src/main/java/eu/darken/myperm/apps/core/container/PrimaryProfilePkg.kt index b265fae0..a4eebc90 100644 --- a/app/src/main/java/eu/darken/myperm/apps/core/container/PrimaryProfilePkg.kt +++ b/app/src/main/java/eu/darken/myperm/apps/core/container/PrimaryProfilePkg.kt @@ -13,6 +13,7 @@ import eu.darken.myperm.apps.core.Pkg import eu.darken.myperm.apps.core.features.* import eu.darken.myperm.apps.core.getIcon2 import eu.darken.myperm.apps.core.getLabel2 +import eu.darken.myperm.common.IPCFunnel import eu.darken.myperm.common.debug.logging.log import eu.darken.myperm.permissions.core.Permission import eu.darken.myperm.permissions.core.known.APerm @@ -81,20 +82,20 @@ class PrimaryProfilePkg( override fun toString(): String = "PrimaryProfilePkg(packageName=$packageName, userHandle=$userHandle)" } -private fun PackageInfo.toNormalPkg(context: Context): PrimaryProfilePkg = PrimaryProfilePkg( +private suspend fun PackageInfo.toNormalPkg(ipcFunnel: IPCFunnel): PrimaryProfilePkg = PrimaryProfilePkg( packageInfo = this, - installerInfo = getInstallerInfo(context.packageManager), - extraPermissions = determineSpecialPermissions(context), - batteryOptimization = determineBatteryOptimization(context), - accessibilityServices = determineAccessibilityServices(context), + installerInfo = getInstallerInfo(ipcFunnel), + extraPermissions = determineSpecialPermissions(ipcFunnel), + batteryOptimization = determineBatteryOptimization(ipcFunnel), + accessibilityServices = determineAccessibilityServices(ipcFunnel), ) -suspend fun getNormalPkgs(context: Context): Collection { +suspend fun getNormalPkgs(ipcFunnel: IPCFunnel): Collection { log(AppRepo.TAG) { "getNormalPkgs()" } return coroutineScope { - context.packageManager.getInstalledPackages(PackageManager.GET_PERMISSIONS) - .map { async { it.toNormalPkg(context) } } + ipcFunnel.packageManager.getInstalledPackages(PackageManager.GET_PERMISSIONS) + .map { async { it.toNormalPkg(ipcFunnel) } } .awaitAll() } } \ No newline at end of file diff --git a/app/src/main/java/eu/darken/myperm/apps/core/container/SecondaryProfilePkg.kt b/app/src/main/java/eu/darken/myperm/apps/core/container/SecondaryProfilePkg.kt index ee4715be..705359df 100644 --- a/app/src/main/java/eu/darken/myperm/apps/core/container/SecondaryProfilePkg.kt +++ b/app/src/main/java/eu/darken/myperm/apps/core/container/SecondaryProfilePkg.kt @@ -1,16 +1,18 @@ package eu.darken.myperm.apps.core.container import android.content.Context -import android.content.pm.* +import android.content.pm.ApplicationInfo +import android.content.pm.PackageInfo +import android.content.pm.PackageManager +import android.content.pm.PermissionInfo import android.graphics.drawable.Drawable import android.os.Process import android.os.UserHandle -import android.os.UserManager -import androidx.core.content.ContextCompat import eu.darken.myperm.apps.core.AppRepo import eu.darken.myperm.apps.core.GET_UNINSTALLED_PACKAGES_COMPAT import eu.darken.myperm.apps.core.Pkg import eu.darken.myperm.apps.core.features.* +import eu.darken.myperm.common.IPCFunnel import eu.darken.myperm.common.debug.logging.Logging.Priority.* import eu.darken.myperm.common.debug.logging.log import eu.darken.myperm.permissions.core.Permission @@ -72,21 +74,18 @@ class SecondaryProfilePkg( override fun toString(): String = "SecondaryProfilePkg(packageName=$packageName, userHandle=$userHandle)" } -suspend fun getSecondaryProfilePkgs(context: Context): Collection = coroutineScope { - val packageManager = context.packageManager - val launcherApps = ContextCompat.getSystemService(context, LauncherApps::class.java)!! - val userManager = ContextCompat.getSystemService(context, UserManager::class.java)!! +suspend fun getSecondaryProfilePkgs(ipcFunnel: IPCFunnel): Collection = coroutineScope { - val profiles = userManager.userProfiles + val profiles = ipcFunnel.userManager.userProfiles() if (profiles.size < 2) return@coroutineScope emptySet() log(AppRepo.TAG, INFO) { "Found multiple user profiles: $profiles" } val extraProfiles = profiles - Process.myUserHandle() - fun determineForHandle(userHandle: UserHandle): Collection { + suspend fun determineForHandle(userHandle: UserHandle): Collection { val launcherInfos = try { - launcherApps.getActivityList(null, userHandle) + ipcFunnel.launcherApps.getActivityList(null, userHandle) } catch (e: SecurityException) { log(AppRepo.TAG, ERROR) { "Failed to retrieve activity list for $userHandle" } emptyList() @@ -95,15 +94,15 @@ suspend fun getSecondaryProfilePkgs(context: Context): Collection = cor return launcherInfos.mapNotNull { lai -> val appInfo = lai.applicationInfo - var pkgInfo = packageManager.getPackageArchiveInfo( + var pkgInfo = ipcFunnel.packageManager.getPackageArchiveInfo( appInfo.packageName, - packageManager.GET_UNINSTALLED_PACKAGES_COMPAT + GET_UNINSTALLED_PACKAGES_COMPAT ) if (pkgInfo == null) { log(AppRepo.TAG, VERBOSE) { "Failed to get info from packagemanager for $appInfo" } pkgInfo = - packageManager.getPackageArchiveInfo(appInfo.sourceDir, PackageManager.GET_PERMISSIONS) + ipcFunnel.packageManager.getPackageArchiveInfo(appInfo.sourceDir, PackageManager.GET_PERMISSIONS) } if (pkgInfo == null) { @@ -113,10 +112,10 @@ suspend fun getSecondaryProfilePkgs(context: Context): Collection = cor SecondaryProfilePkg( packageInfo = pkgInfo, - installerInfo = pkgInfo.getInstallerInfo(packageManager), + installerInfo = pkgInfo.getInstallerInfo(ipcFunnel), launcherAppInfo = appInfo, userHandle = userHandle, - extraPermissions = pkgInfo.determineSpecialPermissions(context), + extraPermissions = pkgInfo.determineSpecialPermissions(ipcFunnel), ).also { log(AppRepo.TAG) { "PKG[profile=${userHandle}}: $it" } } } } diff --git a/app/src/main/java/eu/darken/myperm/apps/core/container/SecondaryUserPkg.kt b/app/src/main/java/eu/darken/myperm/apps/core/container/SecondaryUserPkg.kt index a7ed412f..19208983 100644 --- a/app/src/main/java/eu/darken/myperm/apps/core/container/SecondaryUserPkg.kt +++ b/app/src/main/java/eu/darken/myperm/apps/core/container/SecondaryUserPkg.kt @@ -7,11 +7,10 @@ import android.content.pm.PermissionInfo import android.graphics.drawable.Drawable import android.os.Process import android.os.UserHandle -import android.os.UserManager -import androidx.core.content.ContextCompat import eu.darken.myperm.R import eu.darken.myperm.apps.core.* import eu.darken.myperm.apps.core.features.* +import eu.darken.myperm.common.IPCFunnel import eu.darken.myperm.common.debug.logging.log import eu.darken.myperm.permissions.core.Permission import eu.darken.myperm.permissions.core.known.APerm @@ -72,26 +71,23 @@ class SecondaryUserPkg( override fun toString(): String = "SecondaryUserPkg(packageName=$packageName, userHandle=$userHandle)" } -suspend fun getSecondaryUserPkgs(context: Context): Collection = coroutineScope { +suspend fun getSecondaryUserPkgs(ipcFunnel: IPCFunnel): Collection = coroutineScope { log(AppRepo.TAG) { "getSecondaryPkgs()" } - val packageManager = context.packageManager - val normal = packageManager.getInstalledPackages(0).map { it.packageName } - val uninstalled = packageManager.getInstalledPackages( - PackageManager.GET_PERMISSIONS or packageManager.GET_UNINSTALLED_PACKAGES_COMPAT + val normal = ipcFunnel.packageManager.getInstalledPackages(0).map { it.packageName } + val uninstalled = ipcFunnel.packageManager.getInstalledPackages( + PackageManager.GET_PERMISSIONS or GET_UNINSTALLED_PACKAGES_COMPAT ) val newOnes = uninstalled.filter { !normal.contains(it.packageName) } - val userManager = ContextCompat.getSystemService(context, UserManager::class.java)!! - newOnes .map { pkg -> async { SecondaryUserPkg( packageInfo = pkg, - installerInfo = pkg.getInstallerInfo(packageManager), - userHandle = userManager.tryCreateUserHandle(11) ?: Process.myUserHandle(), - extraPermissions = pkg.determineSpecialPermissions(context), + installerInfo = pkg.getInstallerInfo(ipcFunnel), + userHandle = ipcFunnel.userManager.tryCreateUserHandle(11) ?: Process.myUserHandle(), + extraPermissions = pkg.determineSpecialPermissions(ipcFunnel), ).also { log(AppRepo.TAG) { "PKG[secondary]: $it" } } } } diff --git a/app/src/main/java/eu/darken/myperm/apps/core/features/AccessibilityService.kt b/app/src/main/java/eu/darken/myperm/apps/core/features/AccessibilityService.kt index 0fd3d8e3..d58ec00b 100644 --- a/app/src/main/java/eu/darken/myperm/apps/core/features/AccessibilityService.kt +++ b/app/src/main/java/eu/darken/myperm/apps/core/features/AccessibilityService.kt @@ -1,10 +1,9 @@ package eu.darken.myperm.apps.core.features import android.accessibilityservice.AccessibilityServiceInfo -import android.content.Context import android.content.pm.PackageInfo import android.content.pm.PackageManager -import android.view.accessibility.AccessibilityManager +import eu.darken.myperm.common.IPCFunnel import eu.darken.myperm.permissions.core.known.APerm data class AccessibilityService( @@ -12,14 +11,13 @@ data class AccessibilityService( val label: String, ) -fun PackageInfo.determineAccessibilityServices(context: Context): List { - val pm = context.packageManager - val acsMan = context.getSystemService(Context.ACCESSIBILITY_SERVICE) as AccessibilityManager - val pkgInfo = pm.getPackageInfo(packageName, PackageManager.GET_SERVICES) +suspend fun PackageInfo.determineAccessibilityServices(ipcFunnel: IPCFunnel): List { + val pkgInfo = ipcFunnel.packageManager.getPackageInfo(packageName, PackageManager.GET_SERVICES) - val enabledAcs = acsMan.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_ALL_MASK) + val enabledAcs = + ipcFunnel.accessibilityManager.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_ALL_MASK) - return pkgInfo.services + return pkgInfo?.services ?.filter { it.permission == APerm.BIND_ACCESSIBILITY_SERVICE.id.value } ?.map { AccessibilityService( diff --git a/app/src/main/java/eu/darken/myperm/apps/core/features/BatteryOptimization.kt b/app/src/main/java/eu/darken/myperm/apps/core/features/BatteryOptimization.kt index b7e33ae6..f37145e8 100644 --- a/app/src/main/java/eu/darken/myperm/apps/core/features/BatteryOptimization.kt +++ b/app/src/main/java/eu/darken/myperm/apps/core/features/BatteryOptimization.kt @@ -1,8 +1,7 @@ package eu.darken.myperm.apps.core.features -import android.content.Context import android.content.pm.PackageInfo -import android.os.PowerManager +import eu.darken.myperm.common.IPCFunnel import eu.darken.myperm.common.hasApiLevel import eu.darken.myperm.permissions.core.known.APerm @@ -13,15 +12,14 @@ enum class BatteryOptimization { UNKNOWN, } -fun PackageInfo.determineBatteryOptimization(context: Context): BatteryOptimization { +suspend fun PackageInfo.determineBatteryOptimization(ipcFunnel: IPCFunnel): BatteryOptimization { if (!hasApiLevel(23)) return BatteryOptimization.IGNORED if (requestedPermissions == null) return BatteryOptimization.MANAGED_BY_SYSTEM if (requestedPermissions.none { it == APerm.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS.id.value }) { return BatteryOptimization.MANAGED_BY_SYSTEM } - val pwrm = context.applicationContext.getSystemService(Context.POWER_SERVICE) as PowerManager - return if (pwrm.isIgnoringBatteryOptimizations(packageName)) { + return if (ipcFunnel.powerManager.isIgnoringBatteryOptimizations(packageName)) { BatteryOptimization.IGNORED } else { BatteryOptimization.OPTIMIZED diff --git a/app/src/main/java/eu/darken/myperm/apps/core/features/ExtraPermissionScanner.kt b/app/src/main/java/eu/darken/myperm/apps/core/features/ExtraPermissionScanner.kt index adaa82f9..b406190b 100644 --- a/app/src/main/java/eu/darken/myperm/apps/core/features/ExtraPermissionScanner.kt +++ b/app/src/main/java/eu/darken/myperm/apps/core/features/ExtraPermissionScanner.kt @@ -1,16 +1,15 @@ package eu.darken.myperm.apps.core.features -import android.content.Context import android.content.pm.PackageInfo import android.content.pm.PackageManager +import eu.darken.myperm.common.IPCFunnel import eu.darken.myperm.permissions.core.known.AExtraPerm -fun PackageInfo.determineSpecialPermissions(context: Context): Collection { - val pm = context.packageManager +suspend fun PackageInfo.determineSpecialPermissions(ipcFunnel: IPCFunnel): Collection { val permissions = mutableSetOf() val withActivities = try { - pm.getPackageInfo(packageName, PackageManager.GET_ACTIVITIES) + ipcFunnel.packageManager.getPackageInfo(packageName, PackageManager.GET_ACTIVITIES) } catch (e: PackageManager.NameNotFoundException) { null } diff --git a/app/src/main/java/eu/darken/myperm/apps/core/features/InstallerInfo.kt b/app/src/main/java/eu/darken/myperm/apps/core/features/InstallerInfo.kt index 76e872d8..951fc809 100644 --- a/app/src/main/java/eu/darken/myperm/apps/core/features/InstallerInfo.kt +++ b/app/src/main/java/eu/darken/myperm/apps/core/features/InstallerInfo.kt @@ -11,6 +11,7 @@ import eu.darken.myperm.apps.core.Pkg import eu.darken.myperm.apps.core.known.AKnownPkg import eu.darken.myperm.apps.core.known.toKnownPkg import eu.darken.myperm.apps.core.toContainer +import eu.darken.myperm.common.IPCFunnel import eu.darken.myperm.common.debug.logging.Logging.Priority.WARN import eu.darken.myperm.common.debug.logging.asLog import eu.darken.myperm.common.debug.logging.log @@ -50,17 +51,17 @@ fun Installed.isSideloaded(): Boolean { return installerInfo.allInstallers.none { it.id == AKnownPkg.GooglePlay.id } } -fun PackageInfo.getInstallerInfo( - packageManager: PackageManager, +suspend fun PackageInfo.getInstallerInfo( + ipcFunnel: IPCFunnel, ): InstallerInfo = if (hasApiLevel(Build.VERSION_CODES.R)) { - getInstallerInfoApi30(packageManager) + getInstallerInfoApi30(ipcFunnel) } else { - getInstallerInfoLegacy(packageManager) + getInstallerInfoLegacy(ipcFunnel) } -private fun PackageInfo.getInstallerInfoApi30(packageManager: PackageManager): InstallerInfo { +private suspend fun PackageInfo.getInstallerInfoApi30(ipcFunnel: IPCFunnel): InstallerInfo { val sourceInfo = try { - packageManager.getInstallSourceInfo(packageName) + ipcFunnel.packageManager.getInstallSourceInfo(packageName) } catch (_: PackageManager.NameNotFoundException) { null } @@ -83,10 +84,9 @@ private fun PackageInfo.getInstallerInfoApi30(packageManager: PackageManager): I ) } -@Suppress("DEPRECATION") -private fun PackageInfo.getInstallerInfoLegacy(packageManager: PackageManager): InstallerInfo { +private suspend fun PackageInfo.getInstallerInfoLegacy(ipcFunnel: IPCFunnel): InstallerInfo { val installingPkg = try { - packageManager.getInstallerPackageName(packageName) + ipcFunnel.packageManager.getInstallerPackageName(packageName) ?.let { Pkg.Id(it) } ?.let { it.toKnownPkg() ?: it.toContainer() } } catch (e: IllegalArgumentException) { diff --git a/app/src/main/java/eu/darken/myperm/common/IPCFunnel.kt b/app/src/main/java/eu/darken/myperm/common/IPCFunnel.kt new file mode 100644 index 00000000..f481f924 --- /dev/null +++ b/app/src/main/java/eu/darken/myperm/common/IPCFunnel.kt @@ -0,0 +1,124 @@ +package eu.darken.myperm.common + +import android.accessibilityservice.AccessibilityServiceInfo +import android.content.Context +import android.content.pm.LauncherActivityInfo +import android.content.pm.PackageInfo +import android.content.pm.PermissionGroupInfo +import android.content.pm.PermissionInfo +import android.os.UserHandle +import android.os.UserManager +import androidx.core.content.ContextCompat +import dagger.hilt.android.qualifiers.ApplicationContext +import eu.darken.myperm.apps.core.getPackageInfo2 +import eu.darken.myperm.apps.core.getPermissionInfo2 +import eu.darken.myperm.apps.core.tryCreateUserHandle +import eu.darken.myperm.common.debug.logging.log +import eu.darken.myperm.permissions.core.Permission +import kotlinx.coroutines.sync.Semaphore +import kotlinx.coroutines.sync.withPermit +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class IPCFunnel @Inject constructor( + @ApplicationContext private val context: Context, +) { + + private val execLock = Semaphore( + when { + hasApiLevel(31) -> 4 + hasApiLevel(29) -> 3 + hasApiLevel(26) -> 2 + else -> 1 + }.also { log { "IPCFunnel init with parallelization set to $it" } } + ) + + suspend fun execute(block: suspend IPCFunnel.() -> R): R = execLock.withPermit { block(this) } + + val packageManager by lazy { PackageManager2(this) } + + class PackageManager2(private val ipcFunnel: IPCFunnel) { + private val service = ipcFunnel.context.packageManager + suspend fun getPackageInfo(packageName: String, flags: Int) = ipcFunnel.execute { + service.getPackageInfo2(packageName, flags) + } + + suspend fun getInstalledPackages(flags: Int): List = ipcFunnel.execute { + service.getInstalledPackages(flags) + } + + suspend fun getInstallSourceInfo(packageName: String) = ipcFunnel.execute { + service.getInstallSourceInfo(packageName) + } + + suspend fun getPackageArchiveInfo(path: String, flags: Int) = ipcFunnel.execute { + service.getPackageArchiveInfo(path, flags) + } + + @Suppress("DEPRECATION") + suspend fun getInstallerPackageName(packageName: String) = ipcFunnel.execute { + service.getInstallerPackageName(packageName) + } + + suspend fun getAllPermissionGroups(flags: Int): List = ipcFunnel.execute { + service.getAllPermissionGroups(flags) + } + + suspend fun queryPermissionsByGroup(packageName: String?, flags: Int): List = + ipcFunnel.execute { + service.queryPermissionsByGroup(packageName, flags) + } + + suspend fun getPermissionInfo2(permissionId: Permission.Id, flags: Int) = ipcFunnel.execute { + service.getPermissionInfo2(permissionId, flags) + } + } + + + val powerManager by lazy { PowerManager2(this) } + + class PowerManager2(private val ipcFunnel: IPCFunnel) { + private val service = ipcFunnel.context.getSystemService(Context.POWER_SERVICE) as android.os.PowerManager + + suspend fun isIgnoringBatteryOptimizations(packageName: String) = ipcFunnel.execute { + service.isIgnoringBatteryOptimizations(packageName) + } + } + + val accessibilityManager by lazy { AccessibilityManager2(this) } + + class AccessibilityManager2(private val ipcFunnel: IPCFunnel) { + private val service = + ipcFunnel.context.getSystemService(Context.ACCESSIBILITY_SERVICE) as android.view.accessibility.AccessibilityManager + + suspend fun getEnabledAccessibilityServiceList(flags: Int): List = + service.getEnabledAccessibilityServiceList(flags) + } + + val launcherApps by lazy { LauncherApps2(this) } + + class LauncherApps2(private val ipcFunnel: IPCFunnel) { + private val service = + ContextCompat.getSystemService(ipcFunnel.context, android.content.pm.LauncherApps::class.java)!! + + suspend fun getActivityList(packageName: String?, userHandle: UserHandle): List = + ipcFunnel.execute { + service.getActivityList(packageName, userHandle) + } + } + + val userManager by lazy { UserManager2(this) } + + class UserManager2(private val ipcFunnel: IPCFunnel) { + private val service = ContextCompat.getSystemService(ipcFunnel.context, UserManager::class.java)!! + + suspend fun userProfiles(): List = ipcFunnel.execute { + service.userProfiles + } + + suspend fun tryCreateUserHandle(handle: Int) = ipcFunnel.execute { + service.tryCreateUserHandle(handle) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/eu/darken/myperm/common/coil/AppIconFetcher.kt b/app/src/main/java/eu/darken/myperm/common/coil/AppIconFetcher.kt index 34089ec0..c65f7085 100644 --- a/app/src/main/java/eu/darken/myperm/common/coil/AppIconFetcher.kt +++ b/app/src/main/java/eu/darken/myperm/common/coil/AppIconFetcher.kt @@ -1,6 +1,5 @@ package eu.darken.myperm.common.coil -import android.content.pm.PackageManager import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.graphics.drawable.LayerDrawable @@ -17,18 +16,19 @@ import coil.size.pxOrElse import eu.darken.myperm.R import eu.darken.myperm.apps.core.Pkg import eu.darken.myperm.apps.core.features.Installed +import eu.darken.myperm.common.IPCFunnel import eu.darken.myperm.common.dpToPx import eu.darken.myperm.common.getColorForAttr import javax.inject.Inject class AppIconFetcher @Inject constructor( - private val packageManager: PackageManager, + private val ipcFunnel: IPCFunnel, private val data: Pkg, private val options: Options, ) : Fetcher { override suspend fun fetch(): FetchResult { - val baseIcon = data.getIcon(options.context) ?: ColorDrawable(Color.TRANSPARENT) + val baseIcon = ipcFunnel.execute { data.getIcon(options.context) } ?: ColorDrawable(Color.TRANSPARENT) var isSampled = false @@ -67,14 +67,14 @@ class AppIconFetcher @Inject constructor( } class Factory @Inject constructor( - private val packageManager: PackageManager, + private val ipcFunnel: IPCFunnel, ) : Fetcher.Factory { override fun create( data: Pkg, options: Options, imageLoader: ImageLoader - ): Fetcher = AppIconFetcher(packageManager, data, options) + ): Fetcher = AppIconFetcher(ipcFunnel, data, options) } } diff --git a/app/src/main/java/eu/darken/myperm/common/coil/PermissionIconFetcher.kt b/app/src/main/java/eu/darken/myperm/common/coil/PermissionIconFetcher.kt index a347cb2d..041a49da 100644 --- a/app/src/main/java/eu/darken/myperm/common/coil/PermissionIconFetcher.kt +++ b/app/src/main/java/eu/darken/myperm/common/coil/PermissionIconFetcher.kt @@ -1,6 +1,5 @@ package eu.darken.myperm.common.coil -import android.content.pm.PackageManager import android.graphics.Color import android.graphics.drawable.ColorDrawable import coil.ImageLoader @@ -9,30 +8,31 @@ import coil.fetch.DrawableResult import coil.fetch.FetchResult import coil.fetch.Fetcher import coil.request.Options +import eu.darken.myperm.common.IPCFunnel import eu.darken.myperm.permissions.core.Permission import javax.inject.Inject class PermissionIconFetcher @Inject constructor( - private val packageManager: PackageManager, + private val ipcFunnel: IPCFunnel, private val data: Permission, private val options: Options, ) : Fetcher { override suspend fun fetch(): FetchResult = DrawableResult( - drawable = data.getIcon(options.context) ?: ColorDrawable(Color.TRANSPARENT), + drawable = ipcFunnel.execute { data.getIcon(options.context) } ?: ColorDrawable(Color.TRANSPARENT), isSampled = false, dataSource = DataSource.MEMORY ) class Factory @Inject constructor( - private val packageManager: PackageManager, + private val ipcFunnel: IPCFunnel, ) : Fetcher.Factory { override fun create( data: Permission, options: Options, imageLoader: ImageLoader - ): Fetcher = PermissionIconFetcher(packageManager, data, options) + ): Fetcher = PermissionIconFetcher(ipcFunnel, data, options) } } diff --git a/app/src/main/java/eu/darken/myperm/common/dagger/AndroidModule.kt b/app/src/main/java/eu/darken/myperm/common/dagger/AndroidModule.kt index 5dd79bc7..d2c0e873 100644 --- a/app/src/main/java/eu/darken/myperm/common/dagger/AndroidModule.kt +++ b/app/src/main/java/eu/darken/myperm/common/dagger/AndroidModule.kt @@ -2,12 +2,10 @@ package eu.darken.myperm.common.dagger import android.app.Application import android.content.Context -import android.content.pm.PackageManager import androidx.core.app.NotificationManagerCompat import dagger.Module import dagger.Provides import dagger.hilt.InstallIn -import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.components.SingletonComponent import javax.inject.Singleton @@ -19,10 +17,6 @@ class AndroidModule { @Singleton fun context(app: Application): Context = app.applicationContext - @Provides - @Singleton - fun packagemanager(@ApplicationContext context: Context): PackageManager = context.packageManager - @Provides @Singleton fun notificationManager(context: Context): NotificationManagerCompat = diff --git a/app/src/main/java/eu/darken/myperm/permissions/core/PermissionRepo.kt b/app/src/main/java/eu/darken/myperm/permissions/core/PermissionRepo.kt index 1a2dfcb3..64323fcf 100644 --- a/app/src/main/java/eu/darken/myperm/permissions/core/PermissionRepo.kt +++ b/app/src/main/java/eu/darken/myperm/permissions/core/PermissionRepo.kt @@ -8,8 +8,8 @@ import eu.darken.myperm.apps.core.AppRepo import eu.darken.myperm.apps.core.container.BasePkg import eu.darken.myperm.apps.core.features.declaresPermission import eu.darken.myperm.apps.core.features.requestsPermission -import eu.darken.myperm.apps.core.getPermissionInfo2 import eu.darken.myperm.apps.core.known.AKnownPkg +import eu.darken.myperm.common.IPCFunnel import eu.darken.myperm.common.coroutine.AppScope import eu.darken.myperm.common.coroutine.DispatcherProvider import eu.darken.myperm.common.debug.logging.Logging.Priority.ERROR @@ -45,8 +45,8 @@ class PermissionRepo @Inject constructor( @ApplicationContext private val context: Context, @AppScope private val appScope: CoroutineScope, private val dispatcherProvider: DispatcherProvider, - private val packageManager: PackageManager, private val appRepo: AppRepo, + private val ipcFunnel: IPCFunnel, ) { private val refreshTrigger = MutableStateFlow(UUID.randomUUID()) @@ -133,12 +133,12 @@ class PermissionRepo @Inject constructor( private suspend fun getPermissionsAOSP( apps: Collection ): Collection = coroutineScope { - (packageManager.getAllPermissionGroups(0) + listOf(null)) + (ipcFunnel.packageManager.getAllPermissionGroups(0) + listOf(null)) .mapNotNull { permissionGroup -> val name = permissionGroup?.name log(TAG, VERBOSE) { "Querying permission group $name" } try { - packageManager.queryPermissionsByGroup(name, 0) + ipcFunnel.packageManager.queryPermissionsByGroup(name, 0) } catch (e: PackageManager.NameNotFoundException) { log(TAG) { "Failed to retrieve permission group $permissionGroup: $e" } null @@ -191,7 +191,7 @@ class PermissionRepo @Inject constructor( .distinct() .filter { newPerm -> mappedPermissions.none { it.id == newPerm } } .map { id -> - val info = packageManager.getPermissionInfo2(id, PackageManager.GET_META_DATA) + val info = ipcFunnel.packageManager.getPermissionInfo2(id, PackageManager.GET_META_DATA) when { info != null -> info.toDeclaredPermission(apps) else -> id.toUnusedPermission(apps)