diff --git a/app/src/main/kotlin/li/songe/gkd/permission/PermissionState.kt b/app/src/main/kotlin/li/songe/gkd/permission/PermissionState.kt index 26384b60c..e40c0e690 100644 --- a/app/src/main/kotlin/li/songe/gkd/permission/PermissionState.kt +++ b/app/src/main/kotlin/li/songe/gkd/permission/PermissionState.kt @@ -16,6 +16,7 @@ import li.songe.gkd.appScope import li.songe.gkd.shizuku.shizukuCheckGranted import li.songe.gkd.util.initOrResetAppInfoCache import li.songe.gkd.util.launchTry +import li.songe.gkd.util.mayQueryPkgNoAccessFlow import li.songe.gkd.util.toast import kotlin.coroutines.resume import kotlin.coroutines.suspendCoroutine @@ -184,7 +185,7 @@ fun updatePermissionState() { writeSecureSettingsState, shizukuOkState, ).forEach { it.updateAndGet() } - if (canQueryPkgState.stateFlow.value != canQueryPkgState.updateAndGet()) { + if (canQueryPkgState.stateFlow.value != canQueryPkgState.updateAndGet() || mayQueryPkgNoAccessFlow.value) { appScope.launchTry { initOrResetAppInfoCache() } diff --git a/app/src/main/kotlin/li/songe/gkd/ui/component/QueryPkgTipCard.kt b/app/src/main/kotlin/li/songe/gkd/ui/component/QueryPkgTipCard.kt index e05ffafa2..d75f23966 100644 --- a/app/src/main/kotlin/li/songe/gkd/ui/component/QueryPkgTipCard.kt +++ b/app/src/main/kotlin/li/songe/gkd/ui/component/QueryPkgTipCard.kt @@ -58,7 +58,7 @@ fun QueryPkgAuthCard() { ) Spacer(modifier = Modifier.height(4.dp)) Text( - text = if (!canQueryPkg) "如需显示所有应用\n请授予[读取应用列表权限]" else "检测到应用数量过少\n可尝试授予[读取应用列表权限]", + text = if (!canQueryPkg) "如需显示所有应用\n请授予[读取应用列表权限]" else "检测到应用数量过少\n可尝试授予[读取应用列表权限]\n或关闭权限后重新授权", style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant, textAlign = TextAlign.Center, @@ -72,6 +72,7 @@ fun QueryPkgAuthCard() { })) { Text(text = "申请权限") } + Spacer(modifier = Modifier.height(EmptyHeight / 2)) } } } \ No newline at end of file diff --git a/app/src/main/kotlin/li/songe/gkd/util/AppInfoState.kt b/app/src/main/kotlin/li/songe/gkd/util/AppInfoState.kt index 78a34d285..30f0713df 100644 --- a/app/src/main/kotlin/li/songe/gkd/util/AppInfoState.kt +++ b/app/src/main/kotlin/li/songe/gkd/util/AppInfoState.kt @@ -9,6 +9,9 @@ import android.os.Build import com.blankj.utilcode.util.LogUtils import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.debounce +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.update import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.withContext @@ -38,23 +41,25 @@ val orderedAppInfosFlow by lazy { // https://github.com/orgs/gkd-kit/discussions/761 // 某些设备在应用更新后出现权限错乱/缓存错乱 +private const val MINIMUM_NORMAL_APP_SIZE = 8 val mayQueryPkgNoAccessFlow by lazy { appInfoCacheFlow.map(appScope) { c -> - c.values.count { a -> !a.isSystem && !a.hidden && a.id != META.appId } < 8 + c.values.count { a -> !a.isSystem && !a.hidden && a.id != META.appId } < MINIMUM_NORMAL_APP_SIZE } } +private val willUpdateAppIds by lazy { MutableStateFlow(emptySet()) } + private val packageReceiver by lazy { object : BroadcastReceiver() { - /** - * 例: 小米应用商店更新应用产生连续 3个事件: PACKAGE_REMOVED->PACKAGE_ADDED->PACKAGE_REPLACED - * - */ override fun onReceive(context: Context?, intent: Intent?) { val appId = intent?.data?.schemeSpecificPart ?: return if (intent.action == Intent.ACTION_PACKAGE_ADDED || intent.action == Intent.ACTION_PACKAGE_REPLACED || intent.action == Intent.ACTION_PACKAGE_REMOVED) { - // update - updateAppInfo(appId) + /** + * 例: 小米应用商店更新应用产生连续 3个事件: PACKAGE_REMOVED->PACKAGE_ADDED->PACKAGE_REPLACED + * 使用 Flow + debounce 优化合并 + */ + willUpdateAppIds.update { it + appId } } } }.apply { @@ -79,26 +84,31 @@ private val packageReceiver by lazy { } } +private fun getAppInfo(appId: String): AppInfo? { + return try { + app.packageManager.getPackageInfo(appId, 0) + } catch (_: PackageManager.NameNotFoundException) { + null + }?.toAppInfo() +} private val updateAppMutex by lazy { Mutex() } -private fun updateAppInfo(appId: String) { - appScope.launchTry(Dispatchers.IO) { - val packageManager = app.packageManager - updateAppMutex.withLock { - val newMap = appInfoCacheFlow.value.toMutableMap() - val info = try { - packageManager.getPackageInfo(appId, 0) - } catch (_: PackageManager.NameNotFoundException) { - null - } +private suspend fun updateAppInfo(appIds: Set) { + if (appIds.isEmpty()) return + willUpdateAppIds.update { it - appIds } + updateAppMutex.withLock { + LogUtils.d("updateAppInfo", appIds) + val newMap = appInfoCacheFlow.value.toMutableMap() + appIds.forEach { appId -> + val info = getAppInfo(appId) if (info != null) { - newMap[appId] = info.toAppInfo() + newMap[appId] = info } else { newMap.remove(appId) } - appInfoCacheFlow.value = newMap } + appInfoCacheFlow.value = newMap } } @@ -128,5 +138,8 @@ fun initAppState() { packageReceiver appScope.launchTry(Dispatchers.IO) { initOrResetAppInfoCache() + willUpdateAppIds.debounce(1000) + .filter { it.isNotEmpty() } + .collect { updateAppInfo(it) } } } \ No newline at end of file