diff --git a/patch_v2/files_app/files b/patch_v2/files_app/files index 9b0efa3..1fad387 100755 Binary files a/patch_v2/files_app/files and b/patch_v2/files_app/files differ diff --git a/patch_v2/hello_app/hello b/patch_v2/hello_app/hello index 5035c56..681ce29 100755 Binary files a/patch_v2/hello_app/hello and b/patch_v2/hello_app/hello differ diff --git a/patch_v2/meow_launcherd/app_launcher.c b/patch_v2/meow_launcherd/app_launcher.c index b991c46..2b26e06 100644 --- a/patch_v2/meow_launcherd/app_launcher.c +++ b/patch_v2/meow_launcherd/app_launcher.c @@ -1201,6 +1201,9 @@ static void notify_app_crash(const char *pkg, int status) * ① SIGSTOP App → ② 写 /tmp/meow_notif_active(+ /tmp/meow_power_menu_active 让 watchdog 让位) * → ③ pm_capture_app_frame 读回 App 帧当背景 → ④ run_notif_center(apps={a},1) 叠加渲染 * + 接管输入 → ⑤ 关闭后恢复 App 帧 → unlink active → SIGCONT App。 + * 媒体保活分支(定案):当前媒体源==本 App 且 PLAYING(meow_media_app_playing)→ ①不 SIGSTOP、 + * ⑤不 SIGCONT;App 继续跑保 PCM 供流,上屏由 SDK present 层见 ②的标记自抑,输入由 SDK + * 输入线程见标记排空(防面板点击被 App 双重消费)。非播放中 App 维持 SIGSTOP 模板。 * 差异:背景=App 帧(非应用列表);关闭后回 App(非回 run_menu);点通知首期 = dismiss + 关面板 * + SIGCONT 回当前 App(不跨 app 启动,见 NOTIF_CENTER_APP_OVERLAY_PLAN §3.2)。 * App 崩溃探测:run_notif_center 循环内 read /proc//stat 状态位(zombie)周期探测 @@ -1210,14 +1213,25 @@ static void notify_app_crash(const char *pkg, int status) static int run_app_notif_overlay(struct app *a, pid_t pid) { if (!back_buf_ok || !fb) { logmsg("notif-overlay: no back_buf (direct mode) skip"); return 0; } - logmsg("notif-overlay: open (app=%s pid=%d) SIGSTOP", a->name, pid); - if (kill(pid, SIGSTOP) < 0) { - logmsg("notif-overlay: SIGSTOP %d fail: %s", pid, strerror(errno)); + /* 媒体保活(定案):当前媒体源==本前台 App 且 state==PLAYING → 不 SIGSTOP。ncm 等播放类 + * App 的播放线程同进程,冻结即 PCM 断供(真机报告:播放中滑下通知中心音乐停)。改为: + * App 继续跑(音频照常喂 audiod、媒体上报照常),SDK present 层见 /tmp/meow_notif_active + * 自抑上屏(只画进 back_buf 不 present,防重绘穿透叠加层);关闭时不补 SIGCONT(没 STOP 过)。 + * 非播放中 App 维持现状 SIGSTOP。 */ + int keep_running = meow_media_app_playing(a->id); + if (keep_running) { + logmsg("notif-overlay: open (app=%s pid=%d) PLAYING -> no SIGSTOP (SDK present suppressed)", + a->name, pid); } else { - /* 等 App 进入 stopped 态(/proc/pid/stat 状态位 'T';超时兜底);frozen 后才能读回帧 */ - for (int i = 0; i < 100; i++) { - if (proc_is_stopped(pid)) break; - usleep(10000); + logmsg("notif-overlay: open (app=%s pid=%d) SIGSTOP", a->name, pid); + if (kill(pid, SIGSTOP) < 0) { + logmsg("notif-overlay: SIGSTOP %d fail: %s", pid, strerror(errno)); + } else { + /* 等 App 进入 stopped 态(/proc/pid/stat 状态位 'T';超时兜底);frozen 后才能读回帧 */ + for (int i = 0; i < 100; i++) { + if (proc_is_stopped(pid)) break; + usleep(10000); + } } } /* 让位标记:/tmp/meow_notif_active(§10.5 语义同 powmenu_active)。当前 watchdog 只认 @@ -1240,19 +1254,27 @@ static int run_app_notif_overlay(struct app *a, pid_t pid) g_notif_ctrl_pid = 0; int died = g_notif_ctrl_died; - unlink(NOTIF_ACTIVE); - unlink(POWMENU_ACTIVE); if (died) { /* App 已死:不 SIGCONT、不恢复死帧;back_buf 交还 run_menu 统一重绘 */ + unlink(NOTIF_ACTIVE); + unlink(POWMENU_ACTIVE); logmsg("notif-overlay: app died during session -> unified exit path"); return 1; } /* 恢复 App 帧(run_notif_center 关面板后 back_buf 已还原为背景=App 帧;再拍一次兜底 - * 覆盖非动画关闭路径)+ SIGCONT。 */ + * 覆盖非动画关闭路径)。媒体保活路径(keep_running):先恢复帧再 unlink 标记—— + * App 未被冻结仍在跑,标记多留一拍可让 SDK present 自抑覆盖到恢复帧上屏之后, + * 避免「标记先消失 → App 抢在恢复帧前 present 新帧 → 又被旧帧盖回」的一帧回闪。 */ pm_capture_app_frame(); meow_ui_flush(); - kill(pid, SIGCONT); - logmsg("notif-overlay: closed -> SIGCONT app"); + unlink(NOTIF_ACTIVE); + unlink(POWMENU_ACTIVE); + if (!keep_running) { + kill(pid, SIGCONT); + logmsg("notif-overlay: closed -> SIGCONT app"); + } else { + logmsg("notif-overlay: closed -> app never stopped (media keep-alive), no SIGCONT"); + } return 0; } diff --git a/patch_v2/meow_launcherd/meow_launcherd b/patch_v2/meow_launcherd/meow_launcherd index 9db04d5..301978d 100755 Binary files a/patch_v2/meow_launcherd/meow_launcherd and b/patch_v2/meow_launcherd/meow_launcherd differ diff --git a/patch_v2/meow_launcherd/meow_media.c b/patch_v2/meow_launcherd/meow_media.c index 9485aea..9a57c30 100644 --- a/patch_v2/meow_launcherd/meow_media.c +++ b/patch_v2/meow_launcherd/meow_media.c @@ -120,6 +120,13 @@ int meow_media_has_source(void) return (s && s->state != MEOW_MEDIA_STOPPED) ? 1 : 0; } +int meow_media_app_playing(const char *app_id) +{ + const meow_media_session_t *s = meow_media_current(); + if (!s || !app_id || !app_id[0]) return 0; + return (s->state == MEOW_MEDIA_PLAYING && strcmp(s->app_id, app_id) == 0) ? 1 : 0; +} + static int send_playctl(const meow_media_session_t *s, uint32_t cmd, int64_t seek_ms) { if (!s || !s->used || !g_ops || !g_ops->send) return -1; diff --git a/patch_v2/meow_launcherd/meow_media.h b/patch_v2/meow_launcherd/meow_media.h index 9c0133f..95ef3e2 100644 --- a/patch_v2/meow_launcherd/meow_media.h +++ b/patch_v2/meow_launcherd/meow_media.h @@ -72,6 +72,10 @@ const meow_media_session_t *meow_media_current(void); /* 是否有活动媒体源:当前源存在且 state != 0(停止)。通知中心卡片/播放页据此显示。 */ int meow_media_has_source(void); +/* §10.5 叠加会话保活判定:当前源(最近活跃会话)存在、state==PLAYING 且 app_id 匹配。 + * launcher 据此决定通知中心叠加不 SIGSTOP 该 App(保 PCM 供流),SDK present 层自抑上屏。 */ +int meow_media_app_playing(const char *app_id); + /* 向当前源下发 PLAYCTL(卡片按钮/播放页/媒体键/控制器)。返回 0=已发,-1=无源/发送失败。 */ int meow_media_playctl(uint32_t cmd, int64_t seek_ms); diff --git a/patch_v2/meow_launcherd/test_media.c b/patch_v2/meow_launcherd/test_media.c index 243c8eb..f58b5e5 100644 --- a/patch_v2/meow_launcherd/test_media.c +++ b/patch_v2/meow_launcherd/test_media.c @@ -7,6 +7,7 @@ * 4) PLAYCTL 下发字节格式(socketpair 对端可读回 MSG_PLAYCTL 帧,cmd/seek 正确); * 5) meow_media_playctl 无源 → -1; * 6) clear(app) 清会话 → current()=NULL。 + * 8) meow_media_app_playing(§10.5 叠加保活分支:当前源+PLAYING+app_id 匹配才 1)。 * 只依赖 meow_media.c + meow_ipc.h(纯 C),宿主 gcc 直编。 */ #include @@ -170,6 +171,26 @@ int main(void) fill_meta(&m, "", MEOW_MEDIA_PLAYING, 0, 0, "x", "y"); CHECK(meow_media_meta(&m, sv[0]) == -1, "meta empty app_id == -1"); + /* 8) §10.5 叠加保活分支判定 meow_media_app_playing(launcher 不 SIGSTOP 的入口判据) */ + meow_media_clear(NULL); + CHECK(meow_media_app_playing("com.ncm") == 0, "app_playing: no source == 0"); + fill_meta(&m, "com.ncm", MEOW_MEDIA_PLAYING, 1000, 240000, "Song A", "Artist A"); + meow_media_meta(&m, sv[0]); + CHECK(meow_media_app_playing("com.ncm") == 1, "app_playing: current+PLAYING+match == 1"); + CHECK(meow_media_app_playing("com.other") == 0, "app_playing: app_id mismatch == 0"); + CHECK(meow_media_app_playing("") == 0, "app_playing: empty app_id == 0"); + CHECK(meow_media_app_playing(NULL) == 0, "app_playing: NULL app_id == 0"); + fill_meta(&m, "com.ncm", MEOW_MEDIA_PAUSED, 1000, 240000, "Song A", "Artist A"); + meow_media_meta(&m, sv[0]); + CHECK(meow_media_app_playing("com.ncm") == 0, "app_playing: PAUSED == 0 (SIGSTOP as usual)"); + fill_meta(&m, "com.ncm", MEOW_MEDIA_PLAYING, 2000, 240000, "Song A", "Artist A"); + meow_media_meta(&m, sv[0]); + /* 当前源被别的 App 抢走(后者 PAUSED 也抢走「最近活跃」)→ 本 App 播放中也不再保活 */ + fill_meta(&m, "com.player2", MEOW_MEDIA_PAUSED, 0, 180000, "Song B", "Artist B"); + meow_media_meta(&m, sv[0]); + CHECK(meow_media_app_playing("com.ncm") == 0, "app_playing: not current source == 0"); + meow_media_clear(NULL); + printf("\n%s (%d fails)\n", g_fails ? "FAILED" : "ALL PASS", g_fails); return g_fails ? 1 : 0; } diff --git a/patch_v2/meow_launcherd/test_notif_panel b/patch_v2/meow_launcherd/test_notif_panel index 984a0f0..8069403 100755 Binary files a/patch_v2/meow_launcherd/test_notif_panel and b/patch_v2/meow_launcherd/test_notif_panel differ diff --git a/patch_v2/meow_launcherd/test_vol_ramp_jack b/patch_v2/meow_launcherd/test_vol_ramp_jack index 1684324..1126c55 100755 Binary files a/patch_v2/meow_launcherd/test_vol_ramp_jack and b/patch_v2/meow_launcherd/test_vol_ramp_jack differ diff --git a/patch_v2/sdk/meow_ui_gfx.c b/patch_v2/sdk/meow_ui_gfx.c index 45c1a07..f459632 100644 --- a/patch_v2/sdk/meow_ui_gfx.c +++ b/patch_v2/sdk/meow_ui_gfx.c @@ -42,6 +42,11 @@ #define MUI_DEFAULT_W 480 #define MUI_DEFAULT_H 720 +/* §10.5 叠加让位标记:与 launcher meow_launcher_internal.h NOTIF_ACTIVE 同路径。 + * 通知中心叠加会话期存在;宿主/单测可经 MEOW_NOTIF_ACTIVE_FILE 覆写路径(进程内只解析一次)。 */ +#define MEOW_NOTIF_ACTIVE_DEFAULT "/tmp/meow_notif_active" +#define MEOW_OVERLAY_CHK_MS 200 /* 存在性检查节流:别每帧 stat */ + /* 脏矩形上限(超出合并为全屏) */ #define MUI_DIRTY_MAX 12 @@ -939,10 +944,42 @@ static int statusbar_touched(void) return 0; } +/* ---- §10.5 叠加让位自抑(present 层)---- + * /tmp/meow_notif_active 存在 = 通知中心叠加会话进行中(launcher 正在 fb 上渲染面板)。 + * App 进程(非系统 UI 渲染者)此时不上屏;200ms 节流缓存存在性(别每帧 stat)。 + * 计数 g_overlay_suppressed 供宿主单测断言(meow_gfx_overlay_suppressed_count)。 */ +static unsigned long long g_overlay_suppressed = 0; + +static int overlay_present_suppressed(void) +{ + if (meow_ui_sys_render_enabled()) return 0; /* launcher(系统 UI)渲染面板,照常上屏 */ + static char s_path[108]; + static int s_path_init = 0; + static unsigned long long s_last_chk = 0; + static int s_last_res = 0; + if (!s_path_init) { + const char *e = getenv("MEOW_NOTIF_ACTIVE_FILE"); + snprintf(s_path, sizeof s_path, "%s", (e && e[0]) ? e : MEOW_NOTIF_ACTIVE_DEFAULT); + s_path_init = 1; + } + unsigned long long now = now_ms(); + if (s_last_chk && now - s_last_chk < MEOW_OVERLAY_CHK_MS) return s_last_res; + s_last_chk = now; + s_last_res = (access(s_path, F_OK) == 0) ? 1 : 0; + return s_last_res; +} + +unsigned long long meow_gfx_overlay_suppressed_count(void) { return g_overlay_suppressed; } + static void present(void) { if (!g_init_ok || !g_back_buf) return; if (!(g_dirty_full || g_ndirty > 0)) return; + /* §10.5 叠加让位自抑(仅 App 进程):App 前台播放中唤起通知中心时 launcher 不 SIGSTOP + * (保 PCM 供流,ncm 播放线程同进程),改由 App 进程在此自抑上屏——绘制照常进 back_buf, + * 只是不 present 到 fb,防 App 重绘穿透 launcher 叠加层。系统 UI 进程(launcher 渲染面板) + * 不抑制。抑制期脏区保留累积(超上限自然升级整帧),标记消失后下一次 present 一次上屏。 */ + if (overlay_present_suppressed()) { g_overlay_suppressed++; return; } /* 帧率门控(A-1/A-2,从 launcher 迁入):present 距上次 ≥ period(1000/eff_rate) 才呈现; * 未满周期则保留脏区(不 dirty_reset),下一轮再试。refresh_always_max=1 时跳过门控(恒满速)。 */ unsigned long long now = now_ms(); diff --git a/patch_v2/sdk/meow_ui_input.c b/patch_v2/sdk/meow_ui_input.c index 11dac2d..e105f5a 100644 --- a/patch_v2/sdk/meow_ui_input.c +++ b/patch_v2/sdk/meow_ui_input.c @@ -136,6 +136,30 @@ static int meow_input_jack_debounce(void) return g_jack_changed_at && (now - g_jack_changed_at) < 800; } +/* ---- §10.5 叠加让位:通知中心叠加会话期输入排空(播放中 App 不被 SIGSTOP 的配套)---- + * 媒体播放中的 App 前台唤起通知中心时 launcher 不冻结 App(保 PCM 供流,ncm 播放线程同进程), + * App 输入线程仍在读同一批 evdev 设备(每 fd 各收一份事件副本,与 launcher 互不剥夺)——若不 + * 抑制,面板上的一次点击会被 App 再消费一次(如面板媒体卡片「暂停」与 App 同坐标控件双重触发)。 + * 故标记存在期:排空本进程 fd 队列并丢弃、EVIOCGKEY 位图静默对齐(不产生边沿语义,系统键动作 + * 叠加期由 launcher/watchdog 单侧承担)。200ms 节流缓存存在性(与 present 层同口径,别每圈 stat)。 */ +static int overlay_input_suppressed(void) +{ + static char s_path[108]; + static int s_path_init = 0; + static unsigned long long s_last_chk = 0; + static int s_last_res = 0; + if (!s_path_init) { + const char *e = getenv("MEOW_NOTIF_ACTIVE_FILE"); /* 宿主/单测覆写(进程内只解析一次) */ + snprintf(s_path, sizeof s_path, "%s", (e && e[0]) ? e : "/tmp/meow_notif_active"); + s_path_init = 1; + } + unsigned long long now = now_ms(); + if (s_last_chk && now - s_last_chk < 200) return s_last_res; + s_last_chk = now; + s_last_res = (access(s_path, F_OK) == 0) ? 1 : 0; + return s_last_res; +} + /* ---- 系统按键语义(M2.55:SDK 输入层消化,App 前台也生效)---- * 物理键是系统资源(APPS.md §3.4.1),语义全局统一。本函数在输入线程执行系统动作: * 电源 116 → 息屏/亮屏/长按菜单(内核/sys_server/watchdog),SDK 不动(维持现状); @@ -451,9 +475,34 @@ static void *input_thread(void *arg) } } + int overlay_was = 0; /* §10.5:上一圈是否处于叠加抑制(进入沿复位触摸状态机用) */ while (g_thread_run) { if (nfd == 0) { usleep(20000); continue; } int r = poll(fds, nfd, 20); + /* §10.5 叠加让位:通知中心叠加会话期(标记存在)排空并丢弃本进程事件副本——面板输入 + * 由 launcher 接管,App 不得再消费(防面板点击被 App 双重触发);EVIOCGKEY 位图静默 + * 对齐(不产生边沿语义/系统键动作,解除后不会把面板期按键误判为新边沿)。 */ + if (overlay_input_suppressed()) { + if (!overlay_was) { /* 进入沿:复位触摸状态机,防抑制期丢失抬手致 t_down 卡死 */ + overlay_was = 1; + t_down = 0; t_press_valid = 0; t_origin_valid = 0; + t_cx = t_cy = -1; t_dx = t_dy = 0; t_down_ms = 0; t_mv_x = t_mv_y = -1; + t_long_fired = 0; + } + if (r > 0) + for (int i = 0; i < nfd; i++) { + if (!(fds[i].revents & POLLIN)) continue; + unsigned char junk[64]; + while (read(fds[i].fd, junk, sizeof junk) > 0) { /* 整批丢弃 */ } + } + for (int i = 0; i < nfd; i++) { + unsigned char cur[KEY_MAX / 8 + 1]; + if (ioctl(fds[i].fd, EVIOCGKEY(sizeof cur), cur) == 0) + memcpy(prev_key[i], cur, sizeof cur); + } + continue; + } + overlay_was = 0; if (r < 0) { if (errno != EINTR) usleep(20000); } else if (r > 0) { diff --git a/patch_v2/sdk/meow_ui_internal.h b/patch_v2/sdk/meow_ui_internal.h index 013c73c..c1f895a 100644 --- a/patch_v2/sdk/meow_ui_internal.h +++ b/patch_v2/sdk/meow_ui_internal.h @@ -148,6 +148,10 @@ void meow_gfx_ring_arc(int cx, int cy, int r, int th, int start_deg, /* 是否运行于真实 fb 之上(0 = 头less/离屏,qemu/宿主)。 */ int meow_gfx_is_device(void); +/* §10.5 叠加让位:present 因 /tmp/meow_notif_active 存在而被自抑的累计次数 + * (仅 App 进程会自抑;宿主单测断言用,设备上无调用方)。 */ +unsigned long long meow_gfx_overlay_suppressed_count(void); + /* 中文/日文字库(mfont)是否已加载(状态栏「蓝牙」CJK 与回退 "BT" 二选一)。 */ int meow_gfx_mfont_ready(void); diff --git a/patch_v2/sdk/test_ime_fix b/patch_v2/sdk/test_ime_fix index 0e17466..6d6f73b 100755 Binary files a/patch_v2/sdk/test_ime_fix and b/patch_v2/sdk/test_ime_fix differ diff --git a/patch_v2/sdk/test_meow_ui_widgets b/patch_v2/sdk/test_meow_ui_widgets index d793a4f..ba5e99a 100755 Binary files a/patch_v2/sdk/test_meow_ui_widgets and b/patch_v2/sdk/test_meow_ui_widgets differ diff --git a/patch_v2/sdk/test_notif_gesture b/patch_v2/sdk/test_notif_gesture index fdbfced..d8de637 100755 Binary files a/patch_v2/sdk/test_notif_gesture and b/patch_v2/sdk/test_notif_gesture differ diff --git a/patch_v2/sdk/test_notif_open b/patch_v2/sdk/test_notif_open index 46ec474..76292e8 100755 Binary files a/patch_v2/sdk/test_notif_open and b/patch_v2/sdk/test_notif_open differ diff --git a/patch_v2/sdk/test_overlay_suppress.c b/patch_v2/sdk/test_overlay_suppress.c new file mode 100644 index 0000000..4fa5893 --- /dev/null +++ b/patch_v2/sdk/test_overlay_suppress.c @@ -0,0 +1,97 @@ +/* test_overlay_suppress.c — §10.5 叠加让位 present 自抑宿主验证(离屏 480x720,16bpp)。 + * + * 背景:媒体播放中的 App 前台唤起通知中心时 launcher 不 SIGSTOP(保 PCM 供流),改由 SDK + * present 层见 /tmp/meow_notif_active(宿主用 MEOW_NOTIF_ACTIVE_FILE 覆写)自抑上屏。 + * + * 覆盖: + * T1 无标记:flush 正常上屏(frames_presented 递增,抑制计数 0); + * T2 有标记:flush 被抑制(只画进 back_buf 不 present:frames 不变、抑制计数递增); + * T2b 抑制期第二次 flush 仍被抑制(200ms 节流缓存内行为一致); + * T3 标记消失:下一次 flush 恢复上屏(抑制期累积脏区一次上屏,无需重画); + * T4 系统 UI 进程(launcher,system_mode=1)即使有标记也不抑制(面板必须照常上屏)。 + * + * 编译(宿主 gcc,链真实 gfx/sys/theme/vol/log/widget/input/activity/dialog/ime + 打桩 font/global): + * gcc -Wall -Wextra -o test_overlay_suppress test_overlay_suppress.c test_host_stub.c \ + * meow_ui_gfx.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ + * meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c \ + * meow_ui_draw.c meow_ui_view.c meow_notify_ipc.c \ + * -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread + */ +#include "meow_ui.h" +#include "meow_ui_internal.h" +#include +#include +#include +#include +#include +#include + +#define MARKER "/tmp/test_notif_active_sdk" + +static void marker_write(void) +{ + int fd = open(MARKER, O_WRONLY | O_CREAT | O_TRUNC, 0644); + assert(fd >= 0); + if (write(fd, "1", 1) < 0) assert(0); + close(fd); +} + +int main(void) +{ + setenv("MEOW_UI_DUMP", "/tmp/overlay_suppress.ppm", 1); + setenv("MEOW_NOTIF_ACTIVE_FILE", MARKER, 1); + unlink(MARKER); + meow_ui_opts o = { 480, 720 }; + assert(meow_ui_init(&o) == 0); + meow_ui_set_refresh_always_max(1); /* 绕过帧率门控:每次 flush 都直达 present 判定 */ + + /* T1:无标记正常上屏(默认 App 进程模式:render_enabled==0) */ + assert(meow_ui_sys_render_enabled() == 0); + meow_ui_clear(0x112233); + meow_ui_flush(); + assert(meow_ui_frames_presented() == 1); + assert(meow_gfx_overlay_suppressed_count() == 0); + printf("T1 PASS: no marker -> presented=1 suppressed=0\n"); + + /* T2:有标记 → 抑制(等 >200ms 越过存在性节流缓存) */ + marker_write(); + usleep(250000); + unsigned long long f0 = meow_ui_frames_presented(); + meow_ui_clear(0x223344); + meow_ui_flush(); + assert(meow_ui_frames_presented() == f0); + assert(meow_gfx_overlay_suppressed_count() == 1); + printf("T2 PASS: marker present -> suppressed (frames frozen at %llu)\n", f0); + + /* T2b:抑制期再次 flush 仍抑制(节流缓存内一致) */ + meow_ui_clear(0x334455); + meow_ui_flush(); + assert(meow_ui_frames_presented() == f0); + assert(meow_gfx_overlay_suppressed_count() == 2); + printf("T2b PASS: still suppressed within throttle window\n"); + + /* T3:标记消失 → 恢复上屏(抑制期累积的整帧脏一次上屏,无需重画) */ + unlink(MARKER); + usleep(250000); + meow_ui_flush(); + assert(meow_ui_frames_presented() == f0 + 1); + assert(meow_gfx_overlay_suppressed_count() == 2); + printf("T3 PASS: marker gone -> present resumed (accumulated dirty flushed)\n"); + + /* T4:系统 UI 进程(launcher)不抑制——通知中心面板本身必须照常上屏 */ + meow_ui_sys_set_system_mode(1); + assert(meow_ui_sys_render_enabled() == 1); + marker_write(); + usleep(250000); + unsigned long long f1 = meow_ui_frames_presented(); + meow_ui_clear(0x445566); + meow_ui_flush(); + assert(meow_ui_frames_presented() == f1 + 1); + assert(meow_gfx_overlay_suppressed_count() == 2); /* 不再增长 */ + unlink(MARKER); + printf("T4 PASS: system-UI process (launcher) never suppressed\n"); + + meow_ui_shutdown(); + printf("ALL PASS\n"); + return 0; +} diff --git a/patch_v2/sdk/test_sb_collapse b/patch_v2/sdk/test_sb_collapse index 02fe5c9..385d32b 100755 Binary files a/patch_v2/sdk/test_sb_collapse and b/patch_v2/sdk/test_sb_collapse differ diff --git a/scripts/build/fw_content.conf b/scripts/build/fw_content.conf index f1cdcaa..9e606fb 100644 --- a/scripts/build/fw_content.conf +++ b/scripts/build/fw_content.conf @@ -28,7 +28,7 @@ # ---- 用户态/服务守护二进制(usr/bin,全部 chmod 755 静态 MIPS)---- patch_v2/bootmenu/meow_bootmenu|/usr/bin/meow_bootmenu|4441822d87e76bfce2ce584604ac3830|引导选单 M2.85(sysui让位 agent-216) -patch_v2/meow_launcherd/meow_launcherd|/usr/bin/meow_launcherd|eba4f2b25f01fe756fbf36a9c0844823|主屏 launcher M2.95+(App 前台状态栏 settings.conf mtime 1s 节流重读,修 App 内音量%不刷新;PLAYCTL cmd=6 toggle 透传注释) +patch_v2/meow_launcherd/meow_launcherd|/usr/bin/meow_launcherd|fbb82036566b8808e2449d899ecaf3b0|主屏 launcher M2.95+(§10.5 叠加媒体保活:前台 App 播放中开通知中心不 SIGSTOP,SDK present/输入见 /tmp/meow_notif_active 自抑) patch_v2/meow_watchdog/meow_watchdog|/usr/bin/meow_watchdog|96e80c855e8ca7fd772a2826adbd2639|应用看门狗 M2.95(+音量反转修复) patch_v2/meow_svcd/meow_svcd|/usr/bin/meow_svcd|605646c4cc93f2baf29071ea6bc870ea|服务管理器 M2.77(+崩溃上报 meow_crash agent-187) mips-repo/bins/meow_mdns/bin/meow_mdns|/usr/bin/meow_mdns|d6b0151bda26768f19952dae1342610d|mDNS 应答器 M2.78(启动竞态+换IP重检 agent-194)