From 649fc2c263a5c476f6af9a325002587d9f8f54e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BAnior=20Almeida?= Date: Sun, 15 Feb 2026 12:28:28 -0300 Subject: [PATCH 1/5] Refactor package retrieval to support user profiles --- .../hidemyapplist/util/PackageHelper.kt | 29 ++++++++++++------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/util/PackageHelper.kt b/app/src/main/java/icu/nullptr/hidemyapplist/util/PackageHelper.kt index 0b14f0d1..779512ba 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/util/PackageHelper.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/util/PackageHelper.kt @@ -6,6 +6,8 @@ import android.content.pm.ApplicationInfo import android.content.pm.PackageInfo import android.content.pm.PackageManager import android.graphics.drawable.Drawable +import android.os.UserHandle +import android.os.UserManager import android.util.Log import androidx.core.content.res.ResourcesCompat import androidx.core.graphics.drawable.toDrawable @@ -92,27 +94,32 @@ object PackageHelper { val pm = hmaApp.packageManager if (ConfigManager.packageQueryWorkaround) { - val packages = ServiceClient.getPackageNames(0) ?: arrayOf() - mutableMapOf().also { - for (packageName in packages) { - val packageInfo = ServiceClient.getPackageInfo(packageName, 0)!! - if (packageInfo.packageName in Constants.packagesShouldNotHide) continue - packageInfo.applicationInfo?.let { appInfo -> - val label = pm.getApplicationLabel(appInfo).toString() - val icon = loadAppIconFromAppInfo(appInfo) - it[packageInfo.packageName] = PackageCache(packageInfo, label, icon) + val um = hmaApp.getSystemService(Context.USER_SERVICE) as UserManager + mutableMapOf().also { cacheMap -> + for (userProfile: UserHandle in um.userProfiles) { + val packages = ServiceClient.getPackageNames(userProfile.hashCode()) ?: arrayOf() + for (packageName in packages) { + val packageInfo = ServiceClient.getPackageInfo(packageName, userProfile.hashCode())!! + if (packageInfo.packageName in Constants.packagesShouldNotHide) continue + packageInfo.applicationInfo?.let { appInfo -> + val label = pm.getApplicationLabel(appInfo).toString() + val icon = loadAppIconFromAppInfo(appInfo) + if (!cacheMap.containsKey(packageInfo.packageName)) { + cacheMap[packageInfo.packageName] = PackageCache(packageInfo, label, icon); + } + } } } } } else { val packages = pm.getInstalledPackages(0) - mutableMapOf().also { + mutableMapOf().also { cacheMap -> for (packageInfo in packages) { if (packageInfo.packageName in Constants.packagesShouldNotHide) continue packageInfo.applicationInfo?.let { appInfo -> val label = pm.getApplicationLabel(appInfo).toString() val icon = loadAppIconFromAppInfo(appInfo) - it[packageInfo.packageName] = PackageCache(packageInfo, label, icon) + cacheMap[packageInfo.packageName] = PackageCache(packageInfo, label, icon) } } } From 763beccbbd29b7855edc607a9325e5a360e4dd6f Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Mon, 16 Feb 2026 14:08:56 +0300 Subject: [PATCH 2/5] Use alternative package query for multi-user --- .../hidemyapplist/util/PackageHelper.kt | 32 +++++++++++++------ 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/util/PackageHelper.kt b/app/src/main/java/icu/nullptr/hidemyapplist/util/PackageHelper.kt index 779512ba..87e086da 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/util/PackageHelper.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/util/PackageHelper.kt @@ -92,11 +92,12 @@ object PackageHelper { isRefreshing.emit(true) val cache = withContext(Dispatchers.IO) { val pm = hmaApp.packageManager + val um = hmaApp.getSystemService(Context.USER_SERVICE) as UserManager + val profiles = um.userProfiles if (ConfigManager.packageQueryWorkaround) { - val um = hmaApp.getSystemService(Context.USER_SERVICE) as UserManager mutableMapOf().also { cacheMap -> - for (userProfile: UserHandle in um.userProfiles) { + for (userProfile: UserHandle in profiles) { val packages = ServiceClient.getPackageNames(userProfile.hashCode()) ?: arrayOf() for (packageName in packages) { val packageInfo = ServiceClient.getPackageInfo(packageName, userProfile.hashCode())!! @@ -112,14 +113,18 @@ object PackageHelper { } } } else { - val packages = pm.getInstalledPackages(0) mutableMapOf().also { cacheMap -> - for (packageInfo in packages) { - if (packageInfo.packageName in Constants.packagesShouldNotHide) continue - packageInfo.applicationInfo?.let { appInfo -> - val label = pm.getApplicationLabel(appInfo).toString() - val icon = loadAppIconFromAppInfo(appInfo) - cacheMap[packageInfo.packageName] = PackageCache(packageInfo, label, icon) + for (userProfile: UserHandle in profiles) { + val packages = getInstalledPackagesAsUser(pm, userProfile.hashCode()) + for (packageInfo in packages) { + if (packageInfo.packageName in Constants.packagesShouldNotHide) continue + packageInfo.applicationInfo?.let { appInfo -> + val label = pm.getApplicationLabel(appInfo).toString() + val icon = loadAppIconFromAppInfo(appInfo) + if (!cacheMap.containsKey(packageInfo.packageName)) { + cacheMap[packageInfo.packageName] = PackageCache(packageInfo, label, icon) + } + } } } } @@ -210,4 +215,13 @@ object PackageHelper { return pkgInfo.activities?.firstOrNull { it.targetActivity != null }?.asComponentName() } } + + fun getInstalledPackagesAsUser(pm: PackageManager, userId: Int): List { + return if (userId == 0) { + pm.getInstalledPackages(0) + } else { + val packages = ServiceClient.getPackageNames(userId) ?: arrayOf() + packages.mapNotNull { ServiceClient.getPackageInfo(it, userId) } + } + } } From eee448fbcb7d803ed463745816dd4d887075bcd9 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Mon, 16 Feb 2026 15:22:55 +0300 Subject: [PATCH 3/5] Fix preset load for multi-user --- .../icu/nullptr/hidemyapplist/common/AppPresets.kt | 10 +++------- .../icu/nullptr/hidemyapplist/xposed/HMAService.kt | 13 ++++++------- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/common/src/main/java/icu/nullptr/hidemyapplist/common/AppPresets.kt b/common/src/main/java/icu/nullptr/hidemyapplist/common/AppPresets.kt index 3e764fb2..16b87ada 100644 --- a/common/src/main/java/icu/nullptr/hidemyapplist/common/AppPresets.kt +++ b/common/src/main/java/icu/nullptr/hidemyapplist/common/AppPresets.kt @@ -5,7 +5,6 @@ import android.content.pm.IPackageManager import android.util.Log import icu.nullptr.hidemyapplist.common.RiskyPackageUtils.ignoredForRiskyPackagesList import icu.nullptr.hidemyapplist.common.RiskyPackageUtils.tryToAddIntoGMSConnectionList -import icu.nullptr.hidemyapplist.common.Utils.getInstalledApplicationsCompat import icu.nullptr.hidemyapplist.common.Utils.getPackageInfoCompat import icu.nullptr.hidemyapplist.common.app_presets.BasePreset import icu.nullptr.hidemyapplist.common.app_presets.CustomROMPreset @@ -54,10 +53,9 @@ class AppPresets private constructor() { } val presetNames by lazy { presetList.map { it.name }.toTypedArray() } - // fun filterPresetsByName(names: Array) = presetList.filter { names.contains(it.name) } fun getPresetByName(name: String) = presetList.firstOrNull { it.name == name } - fun reloadPresets(pms: IPackageManager, holder: PresetCacheHolder, clearPresets: Boolean): PresetCacheHolder { + fun reloadPresets(appsList: List, holder: PresetCacheHolder, clearPresets: Boolean): PresetCacheHolder { if (holder.cacheVersion == BuildConfig.APP_VERSION_CODE && !clearPresets) { ignoredForRiskyPackagesList.addAll(holder.gmsDependentApps) @@ -68,15 +66,13 @@ class AppPresets private constructor() { return holder } - return reloadPresetsFromScratch(pms) + return reloadPresetsFromScratch(appsList) } - private fun reloadPresetsFromScratch(pms: IPackageManager): PresetCacheHolder { + private fun reloadPresetsFromScratch(appsList: List): PresetCacheHolder { ignoredForRiskyPackagesList.clear() presetList.forEach { it.clearPackageList() } - val appsList = getInstalledApplicationsCompat(pms, 0, 0) - for (appInfo in appsList) { runCatching { tryToAddIntoGMSConnectionList(appInfo, appInfo.packageName) { diff --git a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/HMAService.kt b/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/HMAService.kt index 7d8cfcac..ca6285f4 100644 --- a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/HMAService.kt +++ b/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/HMAService.kt @@ -601,17 +601,16 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { override fun getLogFileLocation(): String = logFile.absolutePath fun reloadPresets(clearPresets: Boolean) { - presetCache = AppPresets.instance.reloadPresets(pms, presetCache, clearPresets) + presetCache = AppPresets.instance.reloadPresets( + Utils.getInstalledApplicationsCompat(pms, 0L, -1), + presetCache, + clearPresets, + ) writePresetCache() logI(TAG, "All presets are loaded") } - override fun reloadPresetsFromScratch() { - presetCache.presetPackageNames.clear() - presetCache.gmsDependentApps.clear() - - reloadPresets(true) - } + override fun reloadPresetsFromScratch() = reloadPresets(true) override fun getDetailedFilterStats() = filterHolder.toString() From 1cc261bcc2695fe88dcdde44513bb4d589eaf731 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Mon, 16 Feb 2026 16:03:43 +0300 Subject: [PATCH 4/5] Add force-stop support etc. for multi-user --- .../nullptr/hidemyapplist/util/PackageHelper.kt | 11 ++++++++--- .../hma_oss/ui/fragment/AppSettingsV2Fragment.kt | 16 ++++++++++++---- .../nullptr/hidemyapplist/xposed/HMAService.kt | 2 +- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/util/PackageHelper.kt b/app/src/main/java/icu/nullptr/hidemyapplist/util/PackageHelper.kt index 87e086da..61c7278f 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/util/PackageHelper.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/util/PackageHelper.kt @@ -36,7 +36,8 @@ object PackageHelper { class PackageCache( val info: PackageInfo, val label: String, - val icon: Drawable + val icon: Drawable, + val userId: Int, ) object Comparators { @@ -106,7 +107,7 @@ object PackageHelper { val label = pm.getApplicationLabel(appInfo).toString() val icon = loadAppIconFromAppInfo(appInfo) if (!cacheMap.containsKey(packageInfo.packageName)) { - cacheMap[packageInfo.packageName] = PackageCache(packageInfo, label, icon); + cacheMap[packageInfo.packageName] = PackageCache(packageInfo, label, icon, userProfile.hashCode()) } } } @@ -122,7 +123,7 @@ object PackageHelper { val label = pm.getApplicationLabel(appInfo).toString() val icon = loadAppIconFromAppInfo(appInfo) if (!cacheMap.containsKey(packageInfo.packageName)) { - cacheMap[packageInfo.packageName] = PackageCache(packageInfo, label, icon) + cacheMap[packageInfo.packageName] = PackageCache(packageInfo, label, icon, userProfile.hashCode()) } } } @@ -175,6 +176,10 @@ object PackageHelper { android.R.drawable.sym_def_app_icon.asDrawable(hmaApp) } + fun loadUserId(packageName: String): Int = runBlocking { + getCacheNoThrow()[packageName]?.userId ?: 0 + } + fun isSystem(packageName: String): Boolean = runBlocking { getCacheNoThrow()[packageName]?.info?.applicationInfo?.flags?.and(ApplicationInfo.FLAG_SYSTEM) != 0 } diff --git a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/AppSettingsV2Fragment.kt b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/AppSettingsV2Fragment.kt index 082c7ad7..f0abee2f 100644 --- a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/AppSettingsV2Fragment.kt +++ b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/AppSettingsV2Fragment.kt @@ -163,7 +163,12 @@ class AppSettingsV2Fragment : Fragment(R.layout.fragment_settings) { private val parent get() = requireParentFragment() as AppSettingsV2Fragment private val pack get() = parent.viewModel.pack - private fun launchMainActivity(packageName: String) { + private fun launchMainActivity(packageName: String, userId: Int) { + if (userId != 0) { + // TODO: Try to find a method to launch apps across user profiles + return + } + try { val pkgMgr = requireContext().packageManager val pkgInfo = pkgMgr.getPackageInfo(packageName, 0) @@ -171,6 +176,8 @@ class AppSettingsV2Fragment : Fragment(R.layout.fragment_settings) { val resolvedIntent = pkgMgr.getLaunchIntentForPackage(packageName) if (resolvedIntent != null) { startActivity(resolvedIntent) + } else { + throw RuntimeException("No main activity found to launch this app") } } else { throw RuntimeException("Package is disabled") @@ -204,14 +211,15 @@ class AppSettingsV2Fragment : Fragment(R.layout.fragment_settings) { R.array.app_action_texts, ) { _, which -> parent.saveConfig() + val userId = PackageHelper.loadUserId(pack.app) when (which) { 0 -> { - ServiceClient.forceStop(pack.app, 0) - launchMainActivity(pack.app) + ServiceClient.forceStop(pack.app, userId) + launchMainActivity(pack.app, userId) } 1 -> { - launchMainActivity(pack.app) + launchMainActivity(pack.app, userId) } } } diff --git a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/HMAService.kt b/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/HMAService.kt index ca6285f4..6bd904c2 100644 --- a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/HMAService.kt +++ b/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/HMAService.kt @@ -204,7 +204,7 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { } private fun installHooks() { - Utils.getInstalledApplicationsCompat(pms, 0, 0).mapNotNullTo(systemApps) { + Utils.getInstalledApplicationsCompat(pms, 0, -1).mapNotNullTo(systemApps) { if (it.flags and ApplicationInfo.FLAG_SYSTEM != 0) it.packageName else null } From 47edfb09e2e723b3ec8c1c4502ffb6c4e2d106a0 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Mon, 16 Feb 2026 20:12:28 +0300 Subject: [PATCH 5/5] Fix preset loader --- .../hidemyapplist/xposed/HMAService.kt | 34 +++++++++++++------ 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/HMAService.kt b/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/HMAService.kt index 6bd904c2..d60618e7 100644 --- a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/HMAService.kt +++ b/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/HMAService.kt @@ -18,7 +18,12 @@ import icu.nullptr.hidemyapplist.common.JsonConfig import icu.nullptr.hidemyapplist.common.PresetCacheHolder import icu.nullptr.hidemyapplist.common.RiskyPackageUtils.appHasGMSConnection import icu.nullptr.hidemyapplist.common.SettingsPresets -import icu.nullptr.hidemyapplist.common.Utils +import icu.nullptr.hidemyapplist.common.Utils.binderLocalScope +import icu.nullptr.hidemyapplist.common.Utils.generateRandomString +import icu.nullptr.hidemyapplist.common.Utils.getInstalledApplicationsCompat +import icu.nullptr.hidemyapplist.common.Utils.getInstalledPackagesCompat +import icu.nullptr.hidemyapplist.common.Utils.getPackageInfoCompat +import icu.nullptr.hidemyapplist.common.Utils.getPackageUidCompat import icu.nullptr.hidemyapplist.common.app_presets.DetectorAppsPreset import icu.nullptr.hidemyapplist.common.settings_presets.ReplacementItem import icu.nullptr.hidemyapplist.xposed.hook.AccessibilityHook @@ -37,6 +42,7 @@ import icu.nullptr.hidemyapplist.xposed.hook.PmsPackageEventsHook import icu.nullptr.hidemyapplist.xposed.hook.ZygoteHook import org.frknkrc44.hma_oss.common.BuildConfig import rikka.hidden.compat.ActivityManagerApis +import rikka.hidden.compat.UserManagerApis import java.io.File import java.util.concurrent.ExecutorService import java.util.concurrent.Executors @@ -117,7 +123,7 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { } } if (!this::dataDir.isInitialized) { - dataDir = "/data/misc/hide_my_applist_" + Utils.generateRandomString(16) + dataDir = "/data/misc/hide_my_applist_" + generateRandomString(16) } File("$dataDir/log").mkdirs() @@ -204,7 +210,7 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { } private fun installHooks() { - Utils.getInstalledApplicationsCompat(pms, 0, -1).mapNotNullTo(systemApps) { + getInstalledApplicationsCompat(pms, 0, 0).mapNotNullTo(systemApps) { if (it.flags and ApplicationInfo.FLAG_SYSTEM != 0) it.packageName else null } @@ -415,7 +421,7 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { if (caller == query && appConfig.excludeTargetInstallationSource) return Constants.FAKE_INSTALLATION_SOURCE_DISABLED try { - val uid = Utils.getPackageUidCompat(pms, query, 0L, callingHandle.hashCode()) + val uid = getPackageUidCompat(pms, query, 0L, callingHandle.hashCode()) logD(TAG, "@shouldHideInstallationSource UID for $caller, ${callingHandle.hashCode()}: $query, $uid") if (uid < 0) return Constants.FAKE_INSTALLATION_SOURCE_DISABLED // invalid package installation source request } catch (e: Throwable) { @@ -559,7 +565,7 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { override fun readConfig() = config.toString() override fun forceStop(packageName: String?, userId: Int) { - Utils.binderLocalScope { + binderLocalScope { runCatching { ActivityManagerApis.forceStopPackage(packageName, userId) }.onFailure { error -> @@ -572,15 +578,15 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { logWithLevel(level, tag, message) } - override fun getPackageNames(userId: Int) = Utils.binderLocalScope { - Utils.getInstalledPackagesCompat(pms, 0L, userId).map { it.packageName }.toTypedArray() + override fun getPackageNames(userId: Int) = binderLocalScope { + getInstalledPackagesCompat(pms, 0L, userId).map { it.packageName }.toTypedArray() } override fun getPackageInfo( packageName: String, userId: Int - ) = Utils.binderLocalScope { - Utils.getPackageInfoCompat(pms, packageName, 0L, userId) + ) = binderLocalScope { + getPackageInfoCompat(pms, packageName, 0L, userId) } override fun listAllSettings(databaseName: String): Array { @@ -601,8 +607,16 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { override fun getLogFileLocation(): String = logFile.absolutePath fun reloadPresets(clearPresets: Boolean) { + val apps = mutableListOf().apply { + binderLocalScope { + UserManagerApis.getUserIdsNoThrow().forEach { id -> + addAll(getInstalledApplicationsCompat(pms, 0L, id)) + } + } + } + presetCache = AppPresets.instance.reloadPresets( - Utils.getInstalledApplicationsCompat(pms, 0L, -1), + apps, presetCache, clearPresets, )