From 58e11e9221a58ce96e5a1325a61b0c7e60b20efc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E5=88=BA=E8=9E=88?= Date: Thu, 28 Nov 2024 22:25:59 +0800 Subject: [PATCH] feat: add accessRestrictedSettings dialog --- .../main/kotlin/li/songe/gkd/MainActivity.kt | 48 ++++++++ .../li/songe/gkd/service/GkdTileService.kt | 13 +++ .../kotlin/li/songe/gkd/ui/AuthA11yPage.kt | 106 +++++++++++++----- 3 files changed, 137 insertions(+), 30 deletions(-) diff --git a/app/src/main/kotlin/li/songe/gkd/MainActivity.kt b/app/src/main/kotlin/li/songe/gkd/MainActivity.kt index 98315d985..4a8b57c71 100644 --- a/app/src/main/kotlin/li/songe/gkd/MainActivity.kt +++ b/app/src/main/kotlin/li/songe/gkd/MainActivity.kt @@ -17,7 +17,9 @@ import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen import androidx.core.view.ViewCompat import androidx.core.view.WindowInsetsCompat @@ -28,6 +30,8 @@ import com.dylanc.activityresult.launcher.PickContentLauncher import com.dylanc.activityresult.launcher.StartActivityLauncher import com.ramcosta.composedestinations.DestinationsNavHost import com.ramcosta.composedestinations.generated.NavGraphs +import com.ramcosta.composedestinations.generated.destinations.AuthA11YPageDestination +import com.ramcosta.composedestinations.utils.toDestinationsNavigator import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.update @@ -93,6 +97,7 @@ class MainActivity : ComponentActivity() { navController = navController, navGraph = NavGraphs.root ) + AccessRestrictedSettingsDlg() ShizukuErrorDialog(mainVm.shizukuErrorFlow) AuthDialog(mainVm.authReasonFlow) BuildDialog(mainVm.dialogFlow) @@ -265,3 +270,46 @@ private fun ShizukuErrorDialog(stateFlow: MutableStateFlow) { ) } } + + +val accessRestrictedSettingsShowFlow = MutableStateFlow(false) + +@Composable +fun AccessRestrictedSettingsDlg() { + val accessRestrictedSettingsShow by accessRestrictedSettingsShowFlow.collectAsState() + val navController = LocalNavController.current + val isA11yPage = navController.currentDestination?.route == AuthA11YPageDestination.route + LaunchedEffect(isA11yPage) { + if (isA11yPage) { + accessRestrictedSettingsShowFlow.value = false + } + } + if (accessRestrictedSettingsShow && !isA11yPage) { + AlertDialog( + title = { + Text(text = "访问受限") + }, + text = { + Text(text = "尽管 GKD 已持有[写入安全设置权限], 但无法生效, 系统可能在更新 GKD 后用更高级的权限(访问受限设置)限制了 GKD, 请重新授权解除限制") + }, + onDismissRequest = { + accessRestrictedSettingsShowFlow.value = false + }, + confirmButton = { + TextButton({ + accessRestrictedSettingsShowFlow.value = false + navController.toDestinationsNavigator().navigate(AuthA11YPageDestination) + }) { + Text(text = "前往授权") + } + }, + dismissButton = { + TextButton({ + accessRestrictedSettingsShowFlow.value = false + }) { + Text(text = "关闭") + } + }, + ) + } +} \ No newline at end of file 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 c3b5203e2..a72839cee 100644 --- a/app/src/main/kotlin/li/songe/gkd/service/GkdTileService.kt +++ b/app/src/main/kotlin/li/songe/gkd/service/GkdTileService.kt @@ -11,6 +11,7 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch +import li.songe.gkd.accessRestrictedSettingsShowFlow import li.songe.gkd.app import li.songe.gkd.appScope import li.songe.gkd.permission.writeSecureSettingsState @@ -125,6 +126,12 @@ fun switchA11yService() = appScope.launchTry(Dispatchers.IO) { } names.add(a11yClsName) updateServiceNames(names) + delay(300) + if (!A11yService.isRunning.value) { + toast("开启无障碍失败") + accessRestrictedSettingsShowFlow.value = true + return@launchTry + } toast("开启无障碍") } } @@ -148,6 +155,12 @@ fun fixRestartService() = appScope.launchTry(Dispatchers.IO) { } names.add(a11yClsName) updateServiceNames(names) + delay(300) + if (!A11yService.isRunning.value) { + toast("重启无障碍失败") + accessRestrictedSettingsShowFlow.value = true + return@launchTry + } toast("重启无障碍") } } 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 02416dcb8..259ce360d 100644 --- a/app/src/main/kotlin/li/songe/gkd/ui/AuthA11yPage.kt +++ b/app/src/main/kotlin/li/songe/gkd/ui/AuthA11yPage.kt @@ -160,36 +160,7 @@ fun AuthA11yPage() { text = "1. 授予[写入安全设置权限]\n2. 授权永久有效, 包含[无障碍权限]\n3. 应用重启后可自动打开无障碍服务\n4. 在通知栏快捷开关可快捷重启, 无感保活" ) if (!writeSecureSettings) { - Row( - modifier = Modifier - .padding(4.dp, 0.dp) - .fillMaxWidth(), - ) { - TextButton(onClick = throttle(fn = vm.viewModelScope.launchAsFn(Dispatchers.IO) { - context.grantPermissionByShizuku() - })) { - Text( - text = "Shizuku授权", - style = MaterialTheme.typography.bodyLarge, - ) - } - TextButton(onClick = { - vm.showCopyDlgFlow.value = true - }) { - Text( - text = "手动授权", - style = MaterialTheme.typography.bodyLarge, - ) - } - TextButton(onClick = throttle(fn = vm.viewModelScope.launchAsFn(Dispatchers.IO) { - grantPermissionByRoot() - })) { - Text( - text = "ROOT授权", - style = MaterialTheme.typography.bodyLarge, - ) - } - } + AuthButtonGroup() } else { Spacer(modifier = Modifier.height(12.dp)) Text( @@ -220,6 +191,44 @@ fun AuthA11yPage() { } Spacer(modifier = Modifier.height(4.dp)) } + if (writeSecureSettings && !a11yRunning) { + Spacer(modifier = Modifier.height(12.dp)) + Card( + modifier = Modifier + .padding(itemHorizontalPadding, 0.dp) + .fillMaxWidth(), + onClick = { } + ) { + Text( + modifier = Modifier.padding(cardHorizontalPadding, 8.dp), + text = "解除可能受到的无障碍限制", + style = MaterialTheme.typography.bodyLarge, + ) + Text( + modifier = Modifier.padding(cardHorizontalPadding, 0.dp), + style = MaterialTheme.typography.bodyMedium, + text = "1.某些系统有更严格的无障碍限制\n2.会在 GKD 更新后重新限制开启\n3.重新授权可解决此问题" + ) + Spacer(modifier = Modifier.height(12.dp)) + Text( + modifier = Modifier.padding(cardHorizontalPadding, 0.dp), + text = "若能正常开启无障碍请忽略此项", + style = MaterialTheme.typography.bodySmall, + ) + AuthButtonGroup() + Text( + modifier = Modifier + .padding(cardHorizontalPadding, 0.dp) + .clickable { + context.openUri("https://gkd.li/?r=2") + }, + text = "其他方式解除限制", + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.primary, + ) + Spacer(modifier = Modifier.height(12.dp)) + } + } } } @@ -321,3 +330,40 @@ private fun grantPermissionByRoot() { p?.destroy() } } + + +@Composable +private fun AuthButtonGroup() { + val context = LocalContext.current as MainActivity + val vm = viewModel() + Row( + modifier = Modifier + .padding(4.dp, 0.dp) + .fillMaxWidth(), + ) { + TextButton(onClick = throttle(fn = vm.viewModelScope.launchAsFn(Dispatchers.IO) { + context.grantPermissionByShizuku() + })) { + Text( + text = "Shizuku授权", + style = MaterialTheme.typography.bodyLarge, + ) + } + TextButton(onClick = { + vm.showCopyDlgFlow.value = true + }) { + Text( + text = "手动授权", + style = MaterialTheme.typography.bodyLarge, + ) + } + TextButton(onClick = throttle(fn = vm.viewModelScope.launchAsFn(Dispatchers.IO) { + grantPermissionByRoot() + })) { + Text( + text = "ROOT授权", + style = MaterialTheme.typography.bodyLarge, + ) + } + } +} \ No newline at end of file