Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 44 additions & 18 deletions app/src/main/java/icu/nullptr/hidemyapplist/util/PackageHelper.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -34,7 +36,8 @@ object PackageHelper {
class PackageCache(
val info: PackageInfo,
val label: String,
val icon: Drawable
val icon: Drawable,
val userId: Int,
)

object Comparators {
Expand Down Expand Up @@ -90,29 +93,39 @@ 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 packages = ServiceClient.getPackageNames(0) ?: arrayOf<String>()
mutableMapOf<String, PackageCache>().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)
mutableMapOf<String, PackageCache>().also { cacheMap ->
for (userProfile: UserHandle in profiles) {
val packages = ServiceClient.getPackageNames(userProfile.hashCode()) ?: arrayOf<String>()
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, userProfile.hashCode())
}
}
}
}
}
} else {
val packages = pm.getInstalledPackages(0)
mutableMapOf<String, PackageCache>().also {
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)
mutableMapOf<String, PackageCache>().also { cacheMap ->
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, userProfile.hashCode())
}
}
}
}
}
Expand Down Expand Up @@ -163,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
}
Expand Down Expand Up @@ -203,4 +220,13 @@ object PackageHelper {
return pkgInfo.activities?.firstOrNull { it.targetActivity != null }?.asComponentName()
}
}

fun getInstalledPackagesAsUser(pm: PackageManager, userId: Int): List<PackageInfo> {
return if (userId == 0) {
pm.getInstalledPackages(0)
} else {
val packages = ServiceClient.getPackageNames(userId) ?: arrayOf<String>()
packages.mapNotNull { ServiceClient.getPackageInfo(it, userId) }
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -163,14 +163,21 @@ 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)
if (pkgInfo.applicationInfo?.enabled == true) {
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")
Expand Down Expand Up @@ -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)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -54,10 +53,9 @@ class AppPresets private constructor() {
}

val presetNames by lazy { presetList.map { it.name }.toTypedArray() }
// fun filterPresetsByName(names: Array<String>) = 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<ApplicationInfo>, holder: PresetCacheHolder, clearPresets: Boolean): PresetCacheHolder {
if (holder.cacheVersion == BuildConfig.APP_VERSION_CODE && !clearPresets) {
ignoredForRiskyPackagesList.addAll(holder.gmsDependentApps)

Expand All @@ -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<ApplicationInfo>): PresetCacheHolder {
ignoredForRiskyPackagesList.clear()
presetList.forEach { it.clearPackageList() }

val appsList = getInstalledApplicationsCompat(pms, 0, 0)

for (appInfo in appsList) {
runCatching {
tryToAddIntoGMSConnectionList(appInfo, appInfo.packageName) {
Expand Down
45 changes: 29 additions & 16 deletions xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/HMAService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -204,7 +210,7 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() {
}

private fun installHooks() {
Utils.getInstalledApplicationsCompat(pms, 0, 0).mapNotNullTo(systemApps) {
getInstalledApplicationsCompat(pms, 0, 0).mapNotNullTo(systemApps) {
if (it.flags and ApplicationInfo.FLAG_SYSTEM != 0) it.packageName else null
}

Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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 ->
Expand All @@ -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<String> {
Expand All @@ -601,17 +607,24 @@ 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)
val apps = mutableListOf<ApplicationInfo>().apply {
binderLocalScope {
UserManagerApis.getUserIdsNoThrow().forEach { id ->
addAll(getInstalledApplicationsCompat(pms, 0L, id))
}
}
}

presetCache = AppPresets.instance.reloadPresets(
apps,
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()

Expand Down
Loading