Skip to content

[Enhancement] launcher 事件晚于应用事件到达,导致“回桌面”判定误清空(附类名区分方案) #585

Open

Description

@Little-JohnKhan

环境

  • AutoJs6 6.7.0
  • Android 16 (API 36),Redmi / HyperOS 3
  • 无 root、无 Shizuku,仅 A11Y

关联

关联 #343、#466。本文不是重复提问。#343 中已用 com.miui.home + 900ms 时间窗回避了"从后台回应用时包名记为桌面"的问题,但该方案依赖单机硬编码。下面补充一个 #343 未覆盖的判定维度(窗口类名),以及误判的时序成因。

现象

用 A11Y 事件做前台感知时,三类不稳定:

  1. 从应用切回桌面后,currentPackage() 滞后,期间仍返回上一个应用
  2. 从最近任务(Recents)返回应用时,被误判为"回到桌面",状态闪断
  3. launcher 事件可能在应用事件之后"补发",导致刚判定完上岛又被清空

发现

1. 同一 launcher 包名下,类名可区分「桌面本体」与「最近任务」

实测日志(com.android.launcher):

桌面本体      com.android.launcher / com.android.launcher.Launcher
最近任务卡片  com.android.launcher / android.widget.ListView

这两者包名完全相同,仅类名不同。因此只按包名判断"是否回到桌面"会把打开最近任务列表误判为已回桌面。

注意:本机最近任务窗口的类名是 android.widget.ListView,而非 RecentsActivity 之类。这说明类名特征因 ROM 而异,建议同时维护

  • 桌面类名白名单:Launcher / Home / Workspace
  • 最近任务类名特征:Recents / Quickstep / Overview / TaskView / RecentApps

并在无法匹配时降级为"不判定",而非强行判定。

2. launcher 事件会晚于应用事件到达

从最近任务点卡片返回应用,实测序列:

[22:54:42] EVT com.android.launcher / android.widget.ListView
[22:54:42] EVT com.tencent.ima / com.tencent.ima.MainActivity
[22:54:43] 焦点已是 com.tencent.ima,但事件源仍报 com.android.launcher
[22:54:44] ~ [22:54:46] 同上报错状态持续

即:应用已获得焦点,launcher 的事件还在后面补发,持续约 4 秒。任何"看到 launcher 包名就认为回桌面"的实现,都会在这段窗口内误清空状态。

而从桌面点图标进入应用则是相反顺序:

[22:57:44] EVT com.android.launcher / com.android.launcher.Launcher   (连续多条)
[22:57:48] EVT org.autojs.autojs6 / ...MainActivity

应用事件最后到达,判定稳定。

结论:事件到达顺序本身就是可用信号,不必靠固定延时去猜。

3. 事件包名可能与真实前台不一致

同一份日志中,事件上报 com.android.launcher,但当时的控件树全部属于目标应用:

⚠ 事件=com.android.launcher 但控件里有 com.tencent.ima
⚠ 事件=com.android.launcher 但控件里有 org.autojs.autojs6

这说明窗口层级退出过程中残留的 launcher 事件,其包名不能直接等同于当前前台。

复现

events.on("window_state_changed", function (e) {
    log(e.getPackageName() + " / " + e.getClassName()
        + "  | currentPackage=" + currentPackage());
});

依次操作:① 桌面点图标进应用 ② 返回桌面 ③ 打开最近任务 ④ 从最近任务点卡片回应用,对比四种路径的事件顺序与 currentPackage() 返回值。

建议

  1. 文档补充示例:给出"用 launcher 包名 + 类名区分桌面/最近任务"的推荐写法,含类名匹配失败时的降级策略
  2. 提供便捷 API:内置常见 launcher 包名集合,提供 isLauncher(pkg) / isRecentsWindow(cls) 之类的判断
  3. 事件驱动的前台获取:除 currentPackage() 外,考虑提供基于窗口事件维护的前台包名(无事件时零开销),比定时轮询更准也更省电
  4. 无特权场景的价值:v6.1 对 currentPackage 准确性的优化走的是 Shizuku > Root > A11Y 优先级,但多数用户既无 root 也无 Shizuku。上述判定完全基于 A11Y 事件,可作为无特权环境下的兜底方案

附

我用上述逻辑写了一套开源的灵动岛方案(AutoJs6 脚本 + 一个极小的通知中转 App,用于绕过 AutoJs6 清单无法声明 POST_PROMOTED_NOTIFICATIONS 的限制):

https://github.com/Little-JohnKhan/notification-island

其中 scripts/island_daemon.js 的回桌面判定按上面三层写的(类名过滤 → 延时复核 → 期间事件撤销),实测把"切应用必闪"降为基本不出现。

Activity

  1. Little-JohnKhan commented on Oct 19, 2026

    @Little-JohnKhan
    Author

    说明:上述行为源于系统无障碍事件机制与 launcher 实现,并非 AutoJs6 的实现问题。此处仅建议在文档中补充判定方案,减少使用者重复踩坑。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions