From 80b2a23c1fb4e5b5ff4fd9cd0fb9383aa1ccb9ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E5=88=BA=E8=9E=88?= Date: Tue, 5 Nov 2024 23:07:34 +0800 Subject: [PATCH] fix: sync auth state --- .../songe/gkd/permission/PermissionState.kt | 6 +++- .../li/songe/gkd/service/GkdTileService.kt | 12 ++++--- .../kotlin/li/songe/gkd/ui/AuthA11yPage.kt | 16 ++++----- .../songe/gkd/ui/component/QueryPkgTipCard.kt | 33 +++++++++++-------- .../kotlin/li/songe/gkd/util/AppInfoState.kt | 11 ++++++- 5 files changed, 50 insertions(+), 28 deletions(-) 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 0ae7c03..26384b6 100644 --- a/app/src/main/kotlin/li/songe/gkd/permission/PermissionState.kt +++ b/app/src/main/kotlin/li/songe/gkd/permission/PermissionState.kt @@ -172,7 +172,11 @@ val shizukuOkState by lazy { ) } -suspend fun updatePermissionState() { +fun startQueryPkgSettingActivity(context: Activity) { + XXPermissions.startPermissionActivity(context, Permission.GET_INSTALLED_APPS) +} + +fun updatePermissionState() { arrayOf( notificationState, canDrawOverlaysState, diff --git a/app/src/main/kotlin/li/songe/gkd/service/GkdTileService.kt b/app/src/main/kotlin/li/songe/gkd/service/GkdTileService.kt index 4c3189e..97cb125 100644 --- a/app/src/main/kotlin/li/songe/gkd/service/GkdTileService.kt +++ b/app/src/main/kotlin/li/songe/gkd/service/GkdTileService.kt @@ -3,19 +3,23 @@ package li.songe.gkd.service import android.provider.Settings import android.service.quicksettings.Tile import android.service.quicksettings.TileService +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.MainScope import kotlinx.coroutines.cancel +import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import li.songe.gkd.app +import li.songe.gkd.appScope import li.songe.gkd.permission.writeSecureSettingsState import li.songe.gkd.util.OnChangeListen import li.songe.gkd.util.OnDestroy import li.songe.gkd.util.OnTileClick import li.songe.gkd.util.componentName import li.songe.gkd.util.lastRestartA11yServiceTimeFlow +import li.songe.gkd.util.launchTry import li.songe.gkd.util.storeFlow import li.songe.gkd.util.toast import li.songe.gkd.util.useLogLifecycle @@ -125,13 +129,13 @@ fun switchA11yService(): Boolean { return true } -fun fixRestartService(): Boolean { +fun fixRestartService() = appScope.launchTry(Dispatchers.IO) { // 1. 服务没有运行 // 2. 用户配置开启了服务 // 3. 有写入系统设置权限 if (!A11yService.isRunning.value && storeFlow.value.enableService && writeSecureSettingsState.updateAndGet()) { val t = System.currentTimeMillis() - if (t - lastRestartA11yServiceTimeFlow.value < 10_000) return false + if (t - lastRestartA11yServiceTimeFlow.value < 5_000) return@launchTry lastRestartA11yServiceTimeFlow.value = t val names = getServiceNames() val a11yBroken = names.contains(a11yClsName) @@ -139,13 +143,13 @@ fun fixRestartService(): Boolean { // 无障碍出现故障, 重启服务 names.remove(a11yClsName) updateServiceNames(names) + // 必须等待一段时间, 否则概率不会触发系统重启无障碍服务 + delay(500) } names.add(a11yClsName) updateServiceNames(names) toast("重启无障碍") - return true } - return false } val a11yClsName by lazy { A11yService::class.componentName.flattenToShortString() } diff --git a/app/src/main/kotlin/li/songe/gkd/ui/AuthA11yPage.kt b/app/src/main/kotlin/li/songe/gkd/ui/AuthA11yPage.kt index f858940..c1cac5b 100644 --- a/app/src/main/kotlin/li/songe/gkd/ui/AuthA11yPage.kt +++ b/app/src/main/kotlin/li/songe/gkd/ui/AuthA11yPage.kt @@ -172,14 +172,6 @@ fun AuthA11yPage() { style = MaterialTheme.typography.bodyLarge, ) } - TextButton(onClick = throttle(fn = vm.viewModelScope.launchAsFn(Dispatchers.IO) { - grantPermissionByRoot() - })) { - Text( - text = "ROOT授权", - style = MaterialTheme.typography.bodyLarge, - ) - } TextButton(onClick = { vm.showCopyDlgFlow.value = true }) { @@ -188,6 +180,14 @@ fun AuthA11yPage() { style = MaterialTheme.typography.bodyLarge, ) } + TextButton(onClick = throttle(fn = vm.viewModelScope.launchAsFn(Dispatchers.IO) { + grantPermissionByRoot() + })) { + Text( + text = "ROOT授权", + style = MaterialTheme.typography.bodyLarge, + ) + } } } else { Spacer(modifier = Modifier.height(12.dp)) 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 1605cd2..e05ffaf 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 @@ -24,15 +24,27 @@ import androidx.lifecycle.viewModelScope import li.songe.gkd.MainActivity import li.songe.gkd.permission.canQueryPkgState import li.songe.gkd.permission.requiredPermission +import li.songe.gkd.permission.startQueryPkgSettingActivity import li.songe.gkd.ui.style.EmptyHeight import li.songe.gkd.util.appRefreshingFlow import li.songe.gkd.util.launchAsFn +import li.songe.gkd.util.mayQueryPkgNoAccessFlow import li.songe.gkd.util.throttle @Composable fun QueryPkgAuthCard() { val canQueryPkg by canQueryPkgState.stateFlow.collectAsState() - if (!canQueryPkg) { + val mayQueryPkgNoAccess by mayQueryPkgNoAccessFlow.collectAsState() + val appRefreshing by appRefreshingFlow.collectAsState() + if (appRefreshing) { + Column( + modifier = Modifier.fillMaxWidth(), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Spacer(modifier = Modifier.height(EmptyHeight / 2)) + CircularProgressIndicator() + } + } else if (!canQueryPkg || mayQueryPkgNoAccess) { val context = LocalContext.current as MainActivity Column( modifier = Modifier.fillMaxWidth(), @@ -46,27 +58,20 @@ fun QueryPkgAuthCard() { ) Spacer(modifier = Modifier.height(4.dp)) Text( - text = "如需显示所有应用\n请授予[读取应用列表权限]", + text = if (!canQueryPkg) "如需显示所有应用\n请授予[读取应用列表权限]" else "检测到应用数量过少\n可尝试授予[读取应用列表权限]", style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant, textAlign = TextAlign.Center, ) TextButton(onClick = throttle(fn = context.mainVm.viewModelScope.launchAsFn { - requiredPermission(context, canQueryPkgState) + if (!canQueryPkg) { + requiredPermission(context, canQueryPkgState) + } else { + startQueryPkgSettingActivity(context) + } })) { Text(text = "申请权限") } } - } else { - val appRefreshing by appRefreshingFlow.collectAsState() - if (appRefreshing) { - Column( - modifier = Modifier.fillMaxWidth(), - horizontalAlignment = Alignment.CenterHorizontally, - ) { - Spacer(modifier = Modifier.height(EmptyHeight / 2)) - CircularProgressIndicator() - } - } } } \ 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 8c21169..78a34d2 100644 --- a/app/src/main/kotlin/li/songe/gkd/util/AppInfoState.kt +++ b/app/src/main/kotlin/li/songe/gkd/util/AppInfoState.kt @@ -12,6 +12,7 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.withContext +import li.songe.gkd.META import li.songe.gkd.app import li.songe.gkd.appScope import li.songe.gkd.data.AppInfo @@ -35,6 +36,14 @@ val orderedAppInfosFlow by lazy { } } +// https://github.com/orgs/gkd-kit/discussions/761 +// 某些设备在应用更新后出现权限错乱/缓存错乱 +val mayQueryPkgNoAccessFlow by lazy { + appInfoCacheFlow.map(appScope) { c -> + c.values.count { a -> !a.isSystem && !a.hidden && a.id != META.appId } < 8 + } +} + private val packageReceiver by lazy { object : BroadcastReceiver() { /** @@ -80,7 +89,7 @@ private fun updateAppInfo(appId: String) { val newMap = appInfoCacheFlow.value.toMutableMap() val info = try { packageManager.getPackageInfo(appId, 0) - } catch (e: PackageManager.NameNotFoundException) { + } catch (_: PackageManager.NameNotFoundException) { null } if (info != null) {