From 5e746241b2f6941940ca74ac34f0d6eb9cda81c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Sun, 11 Jan 2026 10:35:22 +0800 Subject: [PATCH] Add fallback for system getInstalledPackages --- .../nekohasekai/sfa/bg/AppChangeReceiver.kt | 8 +- .../PrivilegeSettingsManageScreen.kt | 88 +------------------ .../profileoverride/PerAppProxyScreen.kt | 9 +- .../screen/settings/ProfileOverrideScreen.kt | 8 +- .../sfa/vendor/PackageQueryManager.kt | 31 ++++--- .../sfa/vendor/PackageQueryManager.kt | 31 ++++--- 6 files changed, 67 insertions(+), 108 deletions(-) diff --git a/app/src/main/java/io/nekohasekai/sfa/bg/AppChangeReceiver.kt b/app/src/main/java/io/nekohasekai/sfa/bg/AppChangeReceiver.kt index 693a34e..0b2a5ad 100644 --- a/app/src/main/java/io/nekohasekai/sfa/bg/AppChangeReceiver.kt +++ b/app/src/main/java/io/nekohasekai/sfa/bg/AppChangeReceiver.kt @@ -61,7 +61,13 @@ class AppChangeReceiver : BroadcastReceiver() { PackageManager.GET_ACTIVITIES or PackageManager.GET_SERVICES or PackageManager.GET_RECEIVERS or PackageManager.GET_PROVIDERS } - val installedPackages = PackageQueryManager.getInstalledPackages(packageManagerFlags) + val retryFlags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + PackageManager.MATCH_UNINSTALLED_PACKAGES + } else { + @Suppress("DEPRECATION") + PackageManager.GET_UNINSTALLED_PACKAGES + } + val installedPackages = PackageQueryManager.getInstalledPackages(packageManagerFlags, retryFlags) val chinaApps = mutableSetOf() for (packageInfo in installedPackages) { if (PerAppProxyScanner.scanChinaPackage(packageInfo)) { diff --git a/app/src/main/java/io/nekohasekai/sfa/compose/screen/privilegesettings/PrivilegeSettingsManageScreen.kt b/app/src/main/java/io/nekohasekai/sfa/compose/screen/privilegesettings/PrivilegeSettingsManageScreen.kt index 3aa6598..b702a50 100644 --- a/app/src/main/java/io/nekohasekai/sfa/compose/screen/privilegesettings/PrivilegeSettingsManageScreen.kt +++ b/app/src/main/java/io/nekohasekai/sfa/compose/screen/privilegesettings/PrivilegeSettingsManageScreen.kt @@ -20,10 +20,7 @@ import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.filled.Clear import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.filled.ContentPaste -import androidx.compose.material.icons.filled.ExpandLess -import androidx.compose.material.icons.filled.ExpandMore import androidx.compose.material.icons.filled.FilterList -import androidx.compose.material.icons.filled.ManageSearch import androidx.compose.material.icons.filled.MoreVert import androidx.compose.material.icons.filled.Search import androidx.compose.material.icons.filled.SelectAll @@ -63,7 +60,6 @@ import io.nekohasekai.sfa.compose.shared.AppSelectionCard import io.nekohasekai.sfa.compose.shared.PackageCache import io.nekohasekai.sfa.compose.shared.SortMode import io.nekohasekai.sfa.compose.shared.buildDisplayPackages -import io.nekohasekai.sfa.compose.screen.profileoverride.PerAppProxyScanner import io.nekohasekai.sfa.utils.PrivilegeSettingsClient import io.nekohasekai.sfa.vendor.PackageQueryManager import io.nekohasekai.sfa.vendor.PrivilegedAccessRequiredException @@ -263,49 +259,19 @@ fun PrivilegeSettingsManageScreen(onBack: () -> Unit) { postSaveSelectedApplications(newSelected) } - fun startScanChinaApps() { - val scanPackages = currentPackages.toList() - if (scanPackages.isEmpty() || isLoading) return - isLoading = true - coroutineScope.launch { - val foundUids = - withContext(Dispatchers.Default) { - scanPackages.mapNotNull { packageCache -> - if (PerAppProxyScanner.scanChinaPackage(packageCache.info)) { - if (getRiskCategory(packageCache) != RiskCategory.NONE) { - null - } else { - packageCache.uid - } - } else { - null - } - }.toSet() - } - if (foundUids.isNotEmpty()) { - postSaveSelectedApplications(selectedUids + foundUids) - } - isLoading = false - } - } - LaunchedEffect(Unit) { isLoading = true val packageManagerFlags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - PackageManager.GET_PERMISSIONS or PackageManager.MATCH_UNINSTALLED_PACKAGES or - PackageManager.GET_ACTIVITIES or PackageManager.GET_SERVICES or - PackageManager.GET_RECEIVERS or PackageManager.GET_PROVIDERS + PackageManager.GET_PERMISSIONS or PackageManager.MATCH_UNINSTALLED_PACKAGES } else { @Suppress("DEPRECATION") - PackageManager.GET_PERMISSIONS or PackageManager.GET_UNINSTALLED_PACKAGES or - PackageManager.GET_ACTIVITIES or PackageManager.GET_SERVICES or - PackageManager.GET_RECEIVERS or PackageManager.GET_PROVIDERS + PackageManager.GET_PERMISSIONS or PackageManager.GET_UNINSTALLED_PACKAGES } val loadResult = withContext(Dispatchers.IO) { try { - val installedPackages = PackageQueryManager.getInstalledPackages(packageManagerFlags) + val installedPackages = PackageQueryManager.getInstalledPackages(packageManagerFlags, packageManagerFlags) val packageManager = context.packageManager val packageCaches = installedPackages.mapNotNull { packageInfo -> @@ -424,9 +390,6 @@ fun PrivilegeSettingsManageScreen(onBack: () -> Unit) { hideDisabledApps = !hideDisabledApps applyFilter() }, - onScanChinaApps = { - startScanChinaApps() - }, onSelectAll = { val newSelected = currentPackages.map { it.uid }.toSet() postSaveSelectedApplications(newSelected) @@ -594,7 +557,6 @@ private fun PrivilegeSettingsMenus( onHideSystemAppsToggle: () -> Unit, onHideOfflineAppsToggle: () -> Unit, onHideDisabledAppsToggle: () -> Unit, - onScanChinaApps: () -> Unit, onSelectAll: () -> Unit, onDeselectAll: () -> Unit, onImport: () -> Unit, @@ -603,7 +565,6 @@ private fun PrivilegeSettingsMenus( var showMainMenu by remember { mutableStateOf(false) } var showSortMenu by remember { mutableStateOf(false) } var showFilterMenu by remember { mutableStateOf(false) } - var showScanMenu by remember { mutableStateOf(false) } var showSelectMenu by remember { mutableStateOf(false) } var showBackupMenu by remember { mutableStateOf(false) } @@ -617,7 +578,6 @@ private fun PrivilegeSettingsMenus( showMainMenu = false showSortMenu = false showFilterMenu = false - showScanMenu = false showSelectMenu = false showBackupMenu = false }, @@ -733,48 +693,6 @@ private fun PrivilegeSettingsMenus( ) } - DropdownMenuItem( - text = { Text(stringResource(R.string.per_app_proxy_scan)) }, - onClick = { showScanMenu = !showScanMenu }, - leadingIcon = { - Icon( - imageVector = Icons.Default.ManageSearch, - contentDescription = null, - tint = MaterialTheme.colorScheme.primary, - ) - }, - trailingIcon = { - Icon( - imageVector = - if (showScanMenu) { - Icons.Default.ExpandLess - } else { - Icons.Default.ExpandMore - }, - contentDescription = null, - ) - }, - ) - if (showScanMenu) { - DropdownMenuItem( - text = { Text(stringResource(R.string.per_app_proxy_scan_china_apps)) }, - onClick = { - onScanChinaApps() - showMainMenu = false - showScanMenu = false - }, - leadingIcon = { - Icon( - imageVector = Icons.Default.ManageSearch, - contentDescription = null, - tint = MaterialTheme.colorScheme.primary, - modifier = Modifier.padding(start = 24.dp), - ) - }, - ) - HorizontalDivider(modifier = Modifier.padding(vertical = 8.dp)) - } - DropdownMenuItem( text = { Text(stringResource(R.string.per_app_proxy_filter)) }, onClick = { showFilterMenu = !showFilterMenu }, diff --git a/app/src/main/java/io/nekohasekai/sfa/compose/screen/profileoverride/PerAppProxyScreen.kt b/app/src/main/java/io/nekohasekai/sfa/compose/screen/profileoverride/PerAppProxyScreen.kt index fbee093..27ecfd0 100644 --- a/app/src/main/java/io/nekohasekai/sfa/compose/screen/profileoverride/PerAppProxyScreen.kt +++ b/app/src/main/java/io/nekohasekai/sfa/compose/screen/profileoverride/PerAppProxyScreen.kt @@ -242,6 +242,13 @@ fun PerAppProxyScreen(onBack: () -> Unit) { PackageManager.GET_ACTIVITIES or PackageManager.GET_SERVICES or PackageManager.GET_RECEIVERS or PackageManager.GET_PROVIDERS } + val retryFlags = + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + PackageManager.MATCH_UNINSTALLED_PACKAGES + } else { + @Suppress("DEPRECATION") + PackageManager.GET_UNINSTALLED_PACKAGES + } val loadResult = withContext(Dispatchers.IO) { try { @@ -251,7 +258,7 @@ fun PerAppProxyScreen(onBack: () -> Unit) { } else { Settings.PER_APP_PROXY_EXCLUDE } - val installedPackages = PackageQueryManager.getInstalledPackages(packageManagerFlags) + val installedPackages = PackageQueryManager.getInstalledPackages(packageManagerFlags, retryFlags) val packageManager = context.packageManager val packageCaches = installedPackages.mapNotNull { packageInfo -> diff --git a/app/src/main/java/io/nekohasekai/sfa/compose/screen/settings/ProfileOverrideScreen.kt b/app/src/main/java/io/nekohasekai/sfa/compose/screen/settings/ProfileOverrideScreen.kt index 023ce80..e65e012 100644 --- a/app/src/main/java/io/nekohasekai/sfa/compose/screen/settings/ProfileOverrideScreen.kt +++ b/app/src/main/java/io/nekohasekai/sfa/compose/screen/settings/ProfileOverrideScreen.kt @@ -704,8 +704,14 @@ private suspend fun scanAllChinaApps(): Set = withContext(Dispatchers.De PackageManager.GET_ACTIVITIES or PackageManager.GET_SERVICES or PackageManager.GET_RECEIVERS or PackageManager.GET_PROVIDERS } + val retryFlags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + PackageManager.MATCH_UNINSTALLED_PACKAGES + } else { + @Suppress("DEPRECATION") + PackageManager.GET_UNINSTALLED_PACKAGES + } - val installedPackages = PackageQueryManager.getInstalledPackages(packageManagerFlags) + val installedPackages = PackageQueryManager.getInstalledPackages(packageManagerFlags, retryFlags) val chinaApps = mutableSetOf() installedPackages.map { packageInfo -> diff --git a/app/src/minApi21/java/io/nekohasekai/sfa/vendor/PackageQueryManager.kt b/app/src/minApi21/java/io/nekohasekai/sfa/vendor/PackageQueryManager.kt index cfab496..c7f19e9 100644 --- a/app/src/minApi21/java/io/nekohasekai/sfa/vendor/PackageQueryManager.kt +++ b/app/src/minApi21/java/io/nekohasekai/sfa/vendor/PackageQueryManager.kt @@ -52,22 +52,33 @@ object PackageQueryManager { _queryMode.value = mode } - suspend fun getInstalledPackages(flags: Int): List { + suspend fun getInstalledPackages(flags: Int, retryFlags: Int): List { return when (val s = strategy) { is PackageQueryStrategy.ForcedRoot -> RootClient.getInstalledPackages(flags) is PackageQueryStrategy.UserSelected -> RootClient.getInstalledPackages(flags) - is PackageQueryStrategy.Direct -> getPackagesViaPackageManager(flags) + is PackageQueryStrategy.Direct -> getPackagesViaPackageManager(flags, retryFlags) } } - private fun getPackagesViaPackageManager(flags: Int): List { - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - Application.packageManager.getInstalledPackages( - PackageManager.PackageInfoFlags.of(flags.toLong()) - ) - } else { - @Suppress("DEPRECATION") - Application.packageManager.getInstalledPackages(flags) + private fun getPackagesViaPackageManager(flags: Int, retryFlags: Int): List { + return try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + Application.packageManager.getInstalledPackages( + PackageManager.PackageInfoFlags.of(flags.toLong()) + ) + } else { + @Suppress("DEPRECATION") + Application.packageManager.getInstalledPackages(flags) + } + } catch (_: RuntimeException) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + Application.packageManager.getInstalledPackages( + PackageManager.PackageInfoFlags.of(retryFlags.toLong()) + ) + } else { + @Suppress("DEPRECATION") + Application.packageManager.getInstalledPackages(retryFlags) + } } } } diff --git a/app/src/minApi23/java/io/nekohasekai/sfa/vendor/PackageQueryManager.kt b/app/src/minApi23/java/io/nekohasekai/sfa/vendor/PackageQueryManager.kt index e1543d7..2421967 100644 --- a/app/src/minApi23/java/io/nekohasekai/sfa/vendor/PackageQueryManager.kt +++ b/app/src/minApi23/java/io/nekohasekai/sfa/vendor/PackageQueryManager.kt @@ -60,25 +60,36 @@ object PackageQueryManager { _queryMode.value = mode } - suspend fun getInstalledPackages(flags: Int): List { + suspend fun getInstalledPackages(flags: Int, retryFlags: Int): List { return when (val s = strategy) { is PackageQueryStrategy.ForcedRoot -> RootClient.getInstalledPackages(flags) is PackageQueryStrategy.UserSelected -> when (s.mode) { Settings.PACKAGE_QUERY_MODE_ROOT -> RootClient.getInstalledPackages(flags) else -> ShizukuPackageManager.getInstalledPackages(flags) } - is PackageQueryStrategy.Direct -> getPackagesViaPackageManager(flags) + is PackageQueryStrategy.Direct -> getPackagesViaPackageManager(flags, retryFlags) } } - private fun getPackagesViaPackageManager(flags: Int): List { - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - Application.packageManager.getInstalledPackages( - PackageManager.PackageInfoFlags.of(flags.toLong()) - ) - } else { - @Suppress("DEPRECATION") - Application.packageManager.getInstalledPackages(flags) + private fun getPackagesViaPackageManager(flags: Int, retryFlags: Int): List { + return try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + Application.packageManager.getInstalledPackages( + PackageManager.PackageInfoFlags.of(flags.toLong()) + ) + } else { + @Suppress("DEPRECATION") + Application.packageManager.getInstalledPackages(flags) + } + } catch (_: RuntimeException) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + Application.packageManager.getInstalledPackages( + PackageManager.PackageInfoFlags.of(retryFlags.toLong()) + ) + } else { + @Suppress("DEPRECATION") + Application.packageManager.getInstalledPackages(retryFlags) + } } } }