perf: blockA11yAppList topAppId

This commit is contained in:
二刺螈 2025-09-21 22:21:45 +08:00
parent 836f29933c
commit 33b1cfef06
8 changed files with 71 additions and 24 deletions

View File

@ -8,6 +8,7 @@ import android.content.ClipboardManager
import android.content.Context
import android.content.Intent
import android.content.pm.ApplicationInfo
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.provider.Settings
import android.view.WindowManager
@ -23,6 +24,7 @@ import li.songe.gkd.service.initA11yWhiteAppList
import li.songe.gkd.shizuku.initShizuku
import li.songe.gkd.store.initStore
import li.songe.gkd.util.AndroidTarget
import li.songe.gkd.util.PKG_FLAGS
import li.songe.gkd.util.SafeR
import li.songe.gkd.util.initAppState
import li.songe.gkd.util.initSubsState
@ -111,6 +113,12 @@ class App : Application() {
return intent.resolveActivity(packageManager)?.packageName
}
fun getPkgInfo(appId: String): PackageInfo? = try {
packageManager.getPackageInfo(appId, PKG_FLAGS)
} catch (_: PackageManager.NameNotFoundException) {
null
}
fun resolveAppId(action: String, category: String? = null): String? {
val intent = Intent(action)
if (category != null) {

View File

@ -192,7 +192,9 @@ class MainActivity : ComponentActivity() {
}
watchKeyboardVisible()
StatusService.autoStart()
topAppIdFlow.value = META.appId
if (storeFlow.value.enableBlockA11yAppList) {
topAppIdFlow.value = META.appId
}
setContent {
val latestInsets = TopAppBarDefaults.windowInsets
val density = LocalDensity.current

View File

@ -20,15 +20,19 @@ import li.songe.gkd.data.AttrInfo
import li.songe.gkd.data.ResetMatchType
import li.songe.gkd.data.ResolvedRule
import li.songe.gkd.data.RuleStatus
import li.songe.gkd.data.isSystem
import li.songe.gkd.db.DbSet
import li.songe.gkd.shizuku.safeInvokeMethod
import li.songe.gkd.store.actionCountFlow
import li.songe.gkd.store.blockA11yAppListFlow
import li.songe.gkd.store.blockMatchAppListFlow
import li.songe.gkd.store.storeFlow
import li.songe.gkd.util.AndroidTarget
import li.songe.gkd.util.PKG_FLAGS
import li.songe.gkd.util.RuleSummary
import li.songe.gkd.util.launchTry
import li.songe.gkd.util.ruleSummaryFlow
import li.songe.gkd.util.systemUiAppId
data class TopActivity(
val appId: String = "",
@ -52,6 +56,10 @@ data class TopActivity(
fun sameAs(a: String, b: String?): Boolean {
return appId == a && activityId == b
}
fun sameAs(cn: ComponentName): Boolean {
return appId == cn.packageName && activityId == cn.className
}
}
val topActivityFlow = MutableStateFlow(TopActivity())
@ -242,11 +250,32 @@ var appChangeTime = 0L
var imeAppId = ""
var launcherAppId = ""
var systemRecentCn = ComponentName("", "")
fun updateSystemDefaultAppId() {
launcherAppId = app.resolveAppId(Intent.ACTION_MAIN, Intent.CATEGORY_HOME) ?: ""
imeAppId = app.getSecureString(Settings.Secure.DEFAULT_INPUT_METHOD)
?.let(ComponentName::unflattenFromString)?.packageName ?: ""
val launcherCn = Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME)
.resolveActivity(app.packageManager)
launcherAppId = launcherCn.packageName
if (app.getPkgInfo(launcherAppId)?.applicationInfo?.isSystem == true) {
systemRecentCn = launcherCn
} else {
safeInvokeMethod {
if (AndroidTarget.P) {
systemRecentCn = ComponentName.unflattenFromString(
app.getString(com.android.internal.R.string.config_recentsComponentName)
) ?: systemRecentCn
}
}
if (systemRecentCn.packageName.isEmpty()) {
// https://github.com/android-cs/8/blob/main/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
systemRecentCn = ComponentName(
systemUiAppId,
"$systemUiAppId.recents.RecentsActivity",
)
}
}
}
private val actionLogMutex = Mutex()

View File

@ -55,6 +55,9 @@ private val PackageInfo.isOverlay: Boolean
false
}
val ApplicationInfo.isSystem: Boolean
get() = flags and ApplicationInfo.FLAG_SYSTEM != 0
fun PackageInfo.toAppInfo(
userId: Int = currentUserId,
) = AppInfo(
@ -63,7 +66,7 @@ fun PackageInfo.toAppInfo(
versionCode = compatVersionCode,
versionName = versionName,
mtime = lastUpdateTime,
isSystem = applicationInfo?.let { it.flags and ApplicationInfo.FLAG_SYSTEM != 0 } ?: false,
isSystem = applicationInfo?.isSystem ?: false,
name = applicationInfo?.run { loadLabel(app.packageManager).toString() } ?: packageName,
hidden = activities?.isEmpty() != false || isOverlay,
enabled = applicationInfo?.enabled ?: true,

View File

@ -10,7 +10,8 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import li.songe.gkd.META
import li.songe.gkd.a11y.launcherAppId
import li.songe.gkd.a11y.systemRecentCn
import li.songe.gkd.a11y.topActivityFlow
import li.songe.gkd.a11y.topAppIdFlow
import li.songe.gkd.accessRestrictedSettingsShowFlow
import li.songe.gkd.app
@ -22,7 +23,6 @@ import li.songe.gkd.store.blockA11yAppListFlow
import li.songe.gkd.store.storeFlow
import li.songe.gkd.util.launchTry
import li.songe.gkd.util.mapState
import li.songe.gkd.util.systemUiAppId
import li.songe.gkd.util.toast
class GkdTileService : BaseTileService() {
@ -141,15 +141,13 @@ val a11yPartDisabledFlow by lazy {
}
}
fun initA11yWhiteAppList() {
val actualFlow = a11yPartDisabledFlow.drop(1)
val actualFlow = topAppIdFlow.drop(1)
appScope.launch(Dispatchers.Main) {
actualFlow.collect { disabled ->
if (!disabled) {
val appId = topAppIdFlow.value
if (appId == launcherAppId || appId == systemUiAppId) {
// 检测最近任务界面,开启或关闭无障碍会造成卡顿
actualFlow.collect { appId ->
if (!blockA11yAppListFlow.value.contains(appId)) {
if (topActivityFlow.value.sameAs(systemRecentCn)) {
// 切换无障碍会造成卡顿,在最近任务界面时,延迟这个卡顿
appScope.launch {
delay(A11Y_WHITE_APP_AWAIT_TIME)
if (appId == topAppIdFlow.value) {
@ -163,8 +161,8 @@ fun initA11yWhiteAppList() {
}
}
appScope.launch(Dispatchers.Main) {
actualFlow.debounce(A11Y_WHITE_APP_AWAIT_TIME).collect { disabled ->
if (disabled) {
actualFlow.debounce(A11Y_WHITE_APP_AWAIT_TIME).collect { appId ->
if (blockA11yAppListFlow.value.contains(appId)) {
forcedUpdateA11yService(true)
}
}

View File

@ -22,7 +22,6 @@ import rikka.shizuku.Shizuku
import rikka.shizuku.ShizukuBinderWrapper
import rikka.shizuku.SystemServiceHelper
// shizuku 会概率断开
inline fun <T> safeInvokeMethod(
block: () -> T
): T? = try {

View File

@ -4,7 +4,6 @@ import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.graphics.drawable.Drawable
import androidx.core.content.ContextCompat
@ -99,12 +98,6 @@ private val packageReceiver by lazy {
const val PKG_FLAGS = PackageManager.MATCH_UNINSTALLED_PACKAGES or PackageManager.GET_ACTIVITIES
private fun getPkgInfo(appId: String): PackageInfo? = try {
app.packageManager.getPackageInfo(appId, PKG_FLAGS)
} catch (_: PackageManager.NameNotFoundException) {
null
}
val updateAppMutex = MutexState()
private fun updateOtherUserAppInfo(userAppInfoMap: Map<String, AppInfo>? = null) {
@ -146,7 +139,7 @@ private fun updatePartAppInfo(
val newAppMap = HashMap(userAppInfoMapFlow.value)
val newIconMap = HashMap(userAppIconMapFlow.value)
appIds.forEach { appId ->
val info = getPkgInfo(appId)
val info = app.getPkgInfo(appId)
if (info != null) {
newAppMap[appId] = info.toAppInfo()
} else {
@ -184,7 +177,7 @@ fun updateAllAppInfo(
)
}.flatten()
.map { it.activityInfo.packageName }.toSet()
.filter { !newAppMap.contains(it) }.mapNotNull { getPkgInfo(it) }
.filter { !newAppMap.contains(it) }.mapNotNull { app.getPkgInfo(it) }
visiblePkgList.forEach { packageInfo ->
newAppMap[packageInfo.packageName] = packageInfo.toAppInfo()
packageInfo.pkgIcon?.let { icon ->

View File

@ -0,0 +1,15 @@
package com.android.internal;
import android.os.Build;
import androidx.annotation.RequiresApi;
/**
* @noinspection unused
*/
public class R {
public static final class string {
@RequiresApi(api = Build.VERSION_CODES.P)
public static int config_recentsComponentName;
}
}