mirror of
https://github.com/gkd-kit/gkd.git
synced 2024-11-16 11:42:22 +08:00
This commit is contained in:
parent
305c65b776
commit
80b2a23c1f
|
@ -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(
|
arrayOf(
|
||||||
notificationState,
|
notificationState,
|
||||||
canDrawOverlaysState,
|
canDrawOverlaysState,
|
||||||
|
|
|
@ -3,19 +3,23 @@ package li.songe.gkd.service
|
||||||
import android.provider.Settings
|
import android.provider.Settings
|
||||||
import android.service.quicksettings.Tile
|
import android.service.quicksettings.Tile
|
||||||
import android.service.quicksettings.TileService
|
import android.service.quicksettings.TileService
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.MainScope
|
import kotlinx.coroutines.MainScope
|
||||||
import kotlinx.coroutines.cancel
|
import kotlinx.coroutines.cancel
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import li.songe.gkd.app
|
import li.songe.gkd.app
|
||||||
|
import li.songe.gkd.appScope
|
||||||
import li.songe.gkd.permission.writeSecureSettingsState
|
import li.songe.gkd.permission.writeSecureSettingsState
|
||||||
import li.songe.gkd.util.OnChangeListen
|
import li.songe.gkd.util.OnChangeListen
|
||||||
import li.songe.gkd.util.OnDestroy
|
import li.songe.gkd.util.OnDestroy
|
||||||
import li.songe.gkd.util.OnTileClick
|
import li.songe.gkd.util.OnTileClick
|
||||||
import li.songe.gkd.util.componentName
|
import li.songe.gkd.util.componentName
|
||||||
import li.songe.gkd.util.lastRestartA11yServiceTimeFlow
|
import li.songe.gkd.util.lastRestartA11yServiceTimeFlow
|
||||||
|
import li.songe.gkd.util.launchTry
|
||||||
import li.songe.gkd.util.storeFlow
|
import li.songe.gkd.util.storeFlow
|
||||||
import li.songe.gkd.util.toast
|
import li.songe.gkd.util.toast
|
||||||
import li.songe.gkd.util.useLogLifecycle
|
import li.songe.gkd.util.useLogLifecycle
|
||||||
|
@ -125,13 +129,13 @@ fun switchA11yService(): Boolean {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
fun fixRestartService(): Boolean {
|
fun fixRestartService() = appScope.launchTry(Dispatchers.IO) {
|
||||||
// 1. 服务没有运行
|
// 1. 服务没有运行
|
||||||
// 2. 用户配置开启了服务
|
// 2. 用户配置开启了服务
|
||||||
// 3. 有写入系统设置权限
|
// 3. 有写入系统设置权限
|
||||||
if (!A11yService.isRunning.value && storeFlow.value.enableService && writeSecureSettingsState.updateAndGet()) {
|
if (!A11yService.isRunning.value && storeFlow.value.enableService && writeSecureSettingsState.updateAndGet()) {
|
||||||
val t = System.currentTimeMillis()
|
val t = System.currentTimeMillis()
|
||||||
if (t - lastRestartA11yServiceTimeFlow.value < 10_000) return false
|
if (t - lastRestartA11yServiceTimeFlow.value < 5_000) return@launchTry
|
||||||
lastRestartA11yServiceTimeFlow.value = t
|
lastRestartA11yServiceTimeFlow.value = t
|
||||||
val names = getServiceNames()
|
val names = getServiceNames()
|
||||||
val a11yBroken = names.contains(a11yClsName)
|
val a11yBroken = names.contains(a11yClsName)
|
||||||
|
@ -139,13 +143,13 @@ fun fixRestartService(): Boolean {
|
||||||
// 无障碍出现故障, 重启服务
|
// 无障碍出现故障, 重启服务
|
||||||
names.remove(a11yClsName)
|
names.remove(a11yClsName)
|
||||||
updateServiceNames(names)
|
updateServiceNames(names)
|
||||||
|
// 必须等待一段时间, 否则概率不会触发系统重启无障碍服务
|
||||||
|
delay(500)
|
||||||
}
|
}
|
||||||
names.add(a11yClsName)
|
names.add(a11yClsName)
|
||||||
updateServiceNames(names)
|
updateServiceNames(names)
|
||||||
toast("重启无障碍")
|
toast("重启无障碍")
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val a11yClsName by lazy { A11yService::class.componentName.flattenToShortString() }
|
val a11yClsName by lazy { A11yService::class.componentName.flattenToShortString() }
|
||||||
|
|
|
@ -172,14 +172,6 @@ fun AuthA11yPage() {
|
||||||
style = MaterialTheme.typography.bodyLarge,
|
style = MaterialTheme.typography.bodyLarge,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
TextButton(onClick = throttle(fn = vm.viewModelScope.launchAsFn(Dispatchers.IO) {
|
|
||||||
grantPermissionByRoot()
|
|
||||||
})) {
|
|
||||||
Text(
|
|
||||||
text = "ROOT授权",
|
|
||||||
style = MaterialTheme.typography.bodyLarge,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
TextButton(onClick = {
|
TextButton(onClick = {
|
||||||
vm.showCopyDlgFlow.value = true
|
vm.showCopyDlgFlow.value = true
|
||||||
}) {
|
}) {
|
||||||
|
@ -188,6 +180,14 @@ fun AuthA11yPage() {
|
||||||
style = MaterialTheme.typography.bodyLarge,
|
style = MaterialTheme.typography.bodyLarge,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
TextButton(onClick = throttle(fn = vm.viewModelScope.launchAsFn(Dispatchers.IO) {
|
||||||
|
grantPermissionByRoot()
|
||||||
|
})) {
|
||||||
|
Text(
|
||||||
|
text = "ROOT授权",
|
||||||
|
style = MaterialTheme.typography.bodyLarge,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Spacer(modifier = Modifier.height(12.dp))
|
Spacer(modifier = Modifier.height(12.dp))
|
||||||
|
|
|
@ -24,15 +24,27 @@ import androidx.lifecycle.viewModelScope
|
||||||
import li.songe.gkd.MainActivity
|
import li.songe.gkd.MainActivity
|
||||||
import li.songe.gkd.permission.canQueryPkgState
|
import li.songe.gkd.permission.canQueryPkgState
|
||||||
import li.songe.gkd.permission.requiredPermission
|
import li.songe.gkd.permission.requiredPermission
|
||||||
|
import li.songe.gkd.permission.startQueryPkgSettingActivity
|
||||||
import li.songe.gkd.ui.style.EmptyHeight
|
import li.songe.gkd.ui.style.EmptyHeight
|
||||||
import li.songe.gkd.util.appRefreshingFlow
|
import li.songe.gkd.util.appRefreshingFlow
|
||||||
import li.songe.gkd.util.launchAsFn
|
import li.songe.gkd.util.launchAsFn
|
||||||
|
import li.songe.gkd.util.mayQueryPkgNoAccessFlow
|
||||||
import li.songe.gkd.util.throttle
|
import li.songe.gkd.util.throttle
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun QueryPkgAuthCard() {
|
fun QueryPkgAuthCard() {
|
||||||
val canQueryPkg by canQueryPkgState.stateFlow.collectAsState()
|
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
|
val context = LocalContext.current as MainActivity
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
@ -46,27 +58,20 @@ fun QueryPkgAuthCard() {
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.height(4.dp))
|
Spacer(modifier = Modifier.height(4.dp))
|
||||||
Text(
|
Text(
|
||||||
text = "如需显示所有应用\n请授予[读取应用列表权限]",
|
text = if (!canQueryPkg) "如需显示所有应用\n请授予[读取应用列表权限]" else "检测到应用数量过少\n可尝试授予[读取应用列表权限]",
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
)
|
)
|
||||||
TextButton(onClick = throttle(fn = context.mainVm.viewModelScope.launchAsFn {
|
TextButton(onClick = throttle(fn = context.mainVm.viewModelScope.launchAsFn {
|
||||||
requiredPermission(context, canQueryPkgState)
|
if (!canQueryPkg) {
|
||||||
|
requiredPermission(context, canQueryPkgState)
|
||||||
|
} else {
|
||||||
|
startQueryPkgSettingActivity(context)
|
||||||
|
}
|
||||||
})) {
|
})) {
|
||||||
Text(text = "申请权限")
|
Text(text = "申请权限")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
val appRefreshing by appRefreshingFlow.collectAsState()
|
|
||||||
if (appRefreshing) {
|
|
||||||
Column(
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
|
||||||
) {
|
|
||||||
Spacer(modifier = Modifier.height(EmptyHeight / 2))
|
|
||||||
CircularProgressIndicator()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -12,6 +12,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import kotlinx.coroutines.sync.withLock
|
import kotlinx.coroutines.sync.withLock
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
import li.songe.gkd.META
|
||||||
import li.songe.gkd.app
|
import li.songe.gkd.app
|
||||||
import li.songe.gkd.appScope
|
import li.songe.gkd.appScope
|
||||||
import li.songe.gkd.data.AppInfo
|
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 {
|
private val packageReceiver by lazy {
|
||||||
object : BroadcastReceiver() {
|
object : BroadcastReceiver() {
|
||||||
/**
|
/**
|
||||||
|
@ -80,7 +89,7 @@ private fun updateAppInfo(appId: String) {
|
||||||
val newMap = appInfoCacheFlow.value.toMutableMap()
|
val newMap = appInfoCacheFlow.value.toMutableMap()
|
||||||
val info = try {
|
val info = try {
|
||||||
packageManager.getPackageInfo(appId, 0)
|
packageManager.getPackageInfo(appId, 0)
|
||||||
} catch (e: PackageManager.NameNotFoundException) {
|
} catch (_: PackageManager.NameNotFoundException) {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
if (info != null) {
|
if (info != null) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user